5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
8 * Please note: This file is automatically generated by a build script. The
9 * full original source is always available from http://simplepie.org/
11 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
12 * All rights reserved.
14 * Redistribution and use in source and binary forms, with or without modification, are
15 * permitted provided that the following conditions are met:
17 * * Redistributions of source code must retain the above copyright notice, this list of
18 * conditions and the following disclaimer.
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.
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
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.
40 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
42 * @author Geoffrey Sneddon
44 * @link http://simplepie.org/ SimplePie
45 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
51 define('SIMPLEPIE_NAME', 'SimplePie');
56 define('SIMPLEPIE_VERSION', '1.3.1');
60 * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc)
62 define('SIMPLEPIE_BUILD', '20121030175911');
65 * SimplePie Website URL
67 define('SIMPLEPIE_URL', 'http://simplepie.org');
71 * @see SimplePie::set_useragent()
73 define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
78 define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
82 * @see SimplePie::set_autodiscovery_level()
84 define('SIMPLEPIE_LOCATOR_NONE', 0);
87 * Feed Link Element Autodiscovery
88 * @see SimplePie::set_autodiscovery_level()
90 define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
93 * Local Feed Extension Autodiscovery
94 * @see SimplePie::set_autodiscovery_level()
96 define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
99 * Local Feed Body Autodiscovery
100 * @see SimplePie::set_autodiscovery_level()
102 define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
105 * Remote Feed Extension Autodiscovery
106 * @see SimplePie::set_autodiscovery_level()
108 define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
111 * Remote Feed Body Autodiscovery
112 * @see SimplePie::set_autodiscovery_level()
114 define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
117 * All Feed Autodiscovery
118 * @see SimplePie::set_autodiscovery_level()
120 define('SIMPLEPIE_LOCATOR_ALL', 31);
125 define('SIMPLEPIE_TYPE_NONE', 0);
130 define('SIMPLEPIE_TYPE_RSS_090', 1);
133 * RSS 0.91 (Netscape)
135 define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
138 * RSS 0.91 (Userland)
140 define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
143 * RSS 0.91 (both Netscape and Userland)
145 define('SIMPLEPIE_TYPE_RSS_091', 6);
150 define('SIMPLEPIE_TYPE_RSS_092', 8);
155 define('SIMPLEPIE_TYPE_RSS_093', 16);
160 define('SIMPLEPIE_TYPE_RSS_094', 32);
165 define('SIMPLEPIE_TYPE_RSS_10', 64);
170 define('SIMPLEPIE_TYPE_RSS_20', 128);
175 define('SIMPLEPIE_TYPE_RSS_RDF', 65);
178 * Non-RDF-based RSS (truly intended as syndication format)
180 define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
185 define('SIMPLEPIE_TYPE_RSS_ALL', 255);
190 define('SIMPLEPIE_TYPE_ATOM_03', 256);
195 define('SIMPLEPIE_TYPE_ATOM_10', 512);
200 define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
205 define('SIMPLEPIE_TYPE_ALL', 1023);
210 define('SIMPLEPIE_CONSTRUCT_NONE', 0);
215 define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
220 define('SIMPLEPIE_CONSTRUCT_HTML', 2);
225 define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
228 * base64-encoded construct
230 define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
235 define('SIMPLEPIE_CONSTRUCT_IRI', 16);
238 * A construct that might be HTML
240 define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
245 define('SIMPLEPIE_CONSTRUCT_ALL', 63);
250 define('SIMPLEPIE_SAME_CASE', 1);
253 * Change to lowercase
255 define('SIMPLEPIE_LOWERCASE', 2);
258 * Change to uppercase
260 define('SIMPLEPIE_UPPERCASE', 4);
263 * PCRE for HTML attributes
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]*');
268 * PCRE for XML attributes
270 define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
275 define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
280 define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
285 define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
290 define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
295 define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
300 define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
303 * RSS 1.0 Content Module Namespace
305 define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
309 * (Stupid, I know, but I'm certain it will confuse people less with support.)
311 define('SIMPLEPIE_NAMESPACE_RSS_20', '');
316 define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
321 define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
324 * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
326 define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
331 define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
334 * Media RSS Namespace
336 define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
339 * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec.
341 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
344 * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5.
346 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
349 * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace.
351 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
354 * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace.
356 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
359 * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL.
361 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
364 * iTunes RSS Namespace
366 define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
371 define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
374 * IANA Link Relations Registry
376 define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
381 define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
386 define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
391 define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
394 * fsockopen() file source
396 define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
401 define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
404 * file_get_contents() file source
406 define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
417 * @var array Raw data
420 public $data = array();
423 * @var mixed Error string
429 * @var object Instance of SimplePie_Sanitize (or other class)
430 * @see SimplePie::set_sanitize_class()
436 * @var string SimplePie Useragent
437 * @see SimplePie::set_useragent()
440 public $useragent = SIMPLEPIE_USERAGENT;
443 * @var string Feed URL
444 * @see SimplePie::set_feed_url()
450 * @var object Instance of SimplePie_File to use as a feed
451 * @see SimplePie::set_file()
457 * @var string Raw feed data
458 * @see SimplePie::set_raw_data()
464 * @var int Timeout for fetching remote files
465 * @see SimplePie::set_timeout()
468 public $timeout = 10;
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()
476 public $force_fsockopen = false;
479 * @var bool Force the given data/URL to be treated as a feed no matter what
481 * @see SimplePie::force_feed()
484 public $force_feed = false;
487 * @var bool Enable/Disable Caching
488 * @see SimplePie::enable_cache()
491 public $cache = true;
494 * @var int Cache duration (in seconds)
495 * @see SimplePie::set_cache_duration()
498 public $cache_duration = 3600;
501 * @var int Auto-discovery cache duration (in seconds)
502 * @see SimplePie::set_autodiscovery_cache_duration()
505 public $autodiscovery_cache_duration = 604800; // 7 Days.
508 * @var string Cache location (relative to executing script)
509 * @see SimplePie::set_cache_location()
512 public $cache_location = './cache';
515 * @var string Function that creates the cache filename
516 * @see SimplePie::set_cache_name_function()
519 public $cache_name_function = 'md5';
522 * @var bool Reorder feed by date descending
523 * @see SimplePie::enable_order_by_date()
526 public $order_by_date = true;
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()
534 public $input_encoding = false;
537 * @var int Feed Autodiscovery Level
538 * @see SimplePie::set_autodiscovery_level()
541 public $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
544 * Class registry object
546 * @var SimplePie_Registry
551 * @var int Maximum number of feeds to check with autodiscovery
552 * @see SimplePie::set_max_checked_feeds()
555 public $max_checked_feeds = 10;
558 * @var array All the feeds found during the autodiscovery process
559 * @see SimplePie::get_all_discovered_feeds()
562 public $all_discovered_feeds = array();
565 * @var string Web-accessible path to the handler_image.php file.
566 * @see SimplePie::set_image_handler()
569 public $image_handler = '';
572 * @var array Stores the URLs when multiple feeds are being initialized.
573 * @see SimplePie::set_feed_url()
576 public $multifeed_url = array();
579 * @var array Stores SimplePie objects when multiple feeds initialized.
582 public $multifeed_objects = array();
585 * @var array Stores the get_object_vars() array for use with multifeeds.
586 * @see SimplePie::set_feed_url()
589 public $config_settings = null;
592 * @var integer Stores the number of items to return per-feed with multifeeds.
593 * @see SimplePie::set_item_limit()
596 public $item_limit = 0;
599 * @var array Stores the default attributes to be stripped by strip_attributes().
600 * @see SimplePie::strip_attributes()
603 public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
606 * @var array Stores the default tags to be stripped by strip_htmltags().
607 * @see SimplePie::strip_htmltags()
610 public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
613 * The SimplePie class contains feed level data and options
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.
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.
624 * @since 1.0 Preview Release
626 public function __construct()
628 if (version_compare(PHP_VERSION, '5.2', '<'))
630 trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.');
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();
638 if (func_num_args() > 0)
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);
643 $args = func_get_args();
644 switch (count($args)) {
646 $this->set_cache_duration($args[2]);
648 $this->set_cache_location($args[1]);
650 $this->set_feed_url($args[0]);
657 * Used for converting object to a string
659 public function __toString()
661 return md5(serialize($this->data));
665 * Remove items that link back to this before destroying this object
667 public function __destruct()
669 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
671 if (!empty($this->data['items']))
673 foreach ($this->data['items'] as $item)
677 unset($item, $this->data['items']);
679 if (!empty($this->data['ordered_items']))
681 foreach ($this->data['ordered_items'] as $item)
685 unset($item, $this->data['ordered_items']);
691 * Force the given data/URL to be treated as a feed
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.
697 * @param bool $enable Force the given data/URL to be treated as a feed
699 public function force_feed($enable = false)
701 $this->force_feed = (bool) $enable;
705 * Set the URL of the feed you want to parse
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.
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.
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.
719 public function set_feed_url($url)
721 $this->multifeed_url = array();
724 foreach ($url as $value)
726 $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1));
731 $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
736 * Set an instance of {@see SimplePie_File} to use as a feed
738 * @param SimplePie_File &$file
739 * @return bool True on success, false on failure
741 public function set_file(&$file)
743 if ($file instanceof SimplePie_File)
745 $this->feed_url = $file->url;
746 $this->file =& $file;
753 * Set the raw XML data to parse
755 * Allows you to use a string of RSS/Atom data instead of a remote feed.
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
762 * @param string $data RSS or Atom data as a string.
763 * @see set_feed_url()
765 public function set_raw_data($data)
767 $this->raw_data = $data;
771 * Set the the default timeout for fetching remote feeds
773 * This allows you to change the maximum time the feed's server to respond
774 * and send the feed back.
777 * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
779 public function set_timeout($timeout = 10)
781 $this->timeout = (int) $timeout;
785 * Force SimplePie to use fsockopen() instead of cURL
788 * @param bool $enable Force fsockopen() to be used
790 public function force_fsockopen($enable = false)
792 $this->force_fsockopen = (bool) $enable;
796 * Enable/disable caching in SimplePie.
798 * This option allows you to disable caching all-together in SimplePie.
799 * However, disabling the cache can lead to longer load times.
801 * @since 1.0 Preview Release
802 * @param bool $enable Enable caching
804 public function enable_cache($enable = true)
806 $this->cache = (bool) $enable;
810 * Set the length of time (in seconds) that the contents of a feed will be
813 * @param int $seconds The feed content cache duration
815 public function set_cache_duration($seconds = 3600)
817 $this->cache_duration = (int) $seconds;
821 * Set the length of time (in seconds) that the autodiscovered feed URL will
824 * @param int $seconds The autodiscovered feed URL cache duration.
826 public function set_autodiscovery_cache_duration($seconds = 604800)
828 $this->autodiscovery_cache_duration = (int) $seconds;
832 * Set the file system location where the cached files should be stored
834 * @param string $location The file system location.
836 public function set_cache_location($location = './cache')
838 $this->cache_location = (string) $location;
842 * Set whether feed items should be sorted into reverse chronological order
844 * @param bool $enable Sort as reverse chronological order.
846 public function enable_order_by_date($enable = true)
848 $this->order_by_date = (bool) $enable;
852 * Set the character encoding used to parse the feed
854 * This overrides the encoding reported by the feed, however it will fall
855 * back to the normal encoding detection if the override fails
857 * @param string $encoding Character encoding
859 public function set_input_encoding($encoding = false)
863 $this->input_encoding = (string) $encoding;
867 $this->input_encoding = false;
872 * Set how much feed autodiscovery to do
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)
883 public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
885 $this->autodiscovery = (int) $level;
889 * Get the class registry
891 * Use this to override SimplePie's default classes
892 * @see SimplePie_Registry
893 * @return SimplePie_Registry
895 public function &get_registry()
897 return $this->registry;
901 * Useful when you are overloading or extending SimplePie's default classes.
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
909 * Set which class SimplePie uses for caching
911 public function set_cache_class($class = 'SimplePie_Cache')
913 return $this->registry->register('Cache', $class, true);
917 * Set which class SimplePie uses for auto-discovery
919 public function set_locator_class($class = 'SimplePie_Locator')
921 return $this->registry->register('Locator', $class, true);
925 * Set which class SimplePie uses for XML parsing
927 public function set_parser_class($class = 'SimplePie_Parser')
929 return $this->registry->register('Parser', $class, true);
933 * Set which class SimplePie uses for remote file fetching
935 public function set_file_class($class = 'SimplePie_File')
937 return $this->registry->register('File', $class, true);
941 * Set which class SimplePie uses for data sanitization
943 public function set_sanitize_class($class = 'SimplePie_Sanitize')
945 return $this->registry->register('Sanitize', $class, true);
949 * Set which class SimplePie uses for handling feed items
951 public function set_item_class($class = 'SimplePie_Item')
953 return $this->registry->register('Item', $class, true);
957 * Set which class SimplePie uses for handling author data
959 public function set_author_class($class = 'SimplePie_Author')
961 return $this->registry->register('Author', $class, true);
965 * Set which class SimplePie uses for handling category data
967 public function set_category_class($class = 'SimplePie_Category')
969 return $this->registry->register('Category', $class, true);
973 * Set which class SimplePie uses for feed enclosures
975 public function set_enclosure_class($class = 'SimplePie_Enclosure')
977 return $this->registry->register('Enclosure', $class, true);
981 * Set which class SimplePie uses for `<media:text>` captions
983 public function set_caption_class($class = 'SimplePie_Caption')
985 return $this->registry->register('Caption', $class, true);
989 * Set which class SimplePie uses for `<media:copyright>`
991 public function set_copyright_class($class = 'SimplePie_Copyright')
993 return $this->registry->register('Copyright', $class, true);
997 * Set which class SimplePie uses for `<media:credit>`
999 public function set_credit_class($class = 'SimplePie_Credit')
1001 return $this->registry->register('Credit', $class, true);
1005 * Set which class SimplePie uses for `<media:rating>`
1007 public function set_rating_class($class = 'SimplePie_Rating')
1009 return $this->registry->register('Rating', $class, true);
1013 * Set which class SimplePie uses for `<media:restriction>`
1015 public function set_restriction_class($class = 'SimplePie_Restriction')
1017 return $this->registry->register('Restriction', $class, true);
1021 * Set which class SimplePie uses for content-type sniffing
1023 public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
1025 return $this->registry->register('Content_Type_Sniffer', $class, true);
1029 * Set which class SimplePie uses item sources
1031 public function set_source_class($class = 'SimplePie_Source')
1033 return $this->registry->register('Source', $class, true);
1038 * Set the user agent string
1040 * @param string $ua New user agent string.
1042 public function set_useragent($ua = SIMPLEPIE_USERAGENT)
1044 $this->useragent = (string) $ua;
1048 * Set callback function to create cache filename with
1050 * @param mixed $function Callback function
1052 public function set_cache_name_function($function = 'md5')
1054 if (is_callable($function))
1056 $this->cache_name_function = $function;
1061 * Set options to make SP as fast as possible
1063 * Forgoes a substantial amount of data sanitization in favor of speed. This
1064 * turns SimplePie into a dumb parser of feeds.
1066 * @param bool $set Whether to set them or not
1068 public function set_stupidly_fast($set = false)
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);
1082 * Set maximum number of feeds to check with autodiscovery
1084 * @param int $max Maximum number of feeds to check
1086 public function set_max_checked_feeds($max = 10)
1088 $this->max_checked_feeds = (int) $max;
1091 public function remove_div($enable = true)
1093 $this->sanitize->remove_div($enable);
1096 public function strip_htmltags($tags = '', $encode = null)
1100 $tags = $this->strip_htmltags;
1102 $this->sanitize->strip_htmltags($tags);
1103 if ($encode !== null)
1105 $this->sanitize->encode_instead_of_strip($tags);
1109 public function encode_instead_of_strip($enable = true)
1111 $this->sanitize->encode_instead_of_strip($enable);
1114 public function strip_attributes($attribs = '')
1116 if ($attribs === '')
1118 $attribs = $this->strip_attributes;
1120 $this->sanitize->strip_attributes($attribs);
1124 * Set the output encoding
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()}.
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.
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
1143 * @param string $encoding
1145 public function set_output_encoding($encoding = 'UTF-8')
1147 $this->sanitize->set_output_encoding($encoding);
1150 public function strip_comments($strip = false)
1152 $this->sanitize->strip_comments($strip);
1156 * Set element/attribute key/value pairs of HTML attributes
1157 * containing URLs that need to be resolved relative to the feed
1159 * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
1160 * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
1164 * @param array|null $element_attribute Element/attribute key/value pairs, null for default
1166 public function set_url_replacements($element_attribute = null)
1168 $this->sanitize->set_url_replacements($element_attribute);
1172 * Set the handler to enable the display of cached images.
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.
1177 public function set_image_handler($page = false, $qs = 'i')
1179 if ($page !== false)
1181 $this->sanitize->set_image_handler($page . '?' . $qs . '=');
1185 $this->image_handler = '';
1190 * Set the limit for items returned per-feed with multifeeds
1192 * @param integer $limit The maximum number of items to return.
1194 public function set_item_limit($limit = 0)
1196 $this->item_limit = (int) $limit;
1200 * Initialize the feed object
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.
1206 * @return boolean True if successful, false otherwise
1208 public function init()
1210 // Check absolute bare minimum requirements.
1211 if (!extension_loaded('xml') || !extension_loaded('pcre'))
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'))
1218 static $xml_is_sane = null;
1219 if ($xml_is_sane === null)
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']);
1232 if (method_exists($this->sanitize, 'set_registry'))
1234 $this->sanitize->set_registry($this->registry);
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);
1242 if (!empty($this->multifeed_url))
1246 $this->multifeed_objects = array();
1247 $this->error = array();
1248 foreach ($this->multifeed_url as $url)
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)
1256 $this->error[$i] = $this->multifeed_objects[$i]->error();
1260 return (bool) $success;
1262 elseif ($this->feed_url === null && $this->raw_data === null)
1267 $this->error = null;
1268 $this->data = array();
1269 $this->multifeed_objects = array();
1272 if ($this->feed_url !== null)
1274 $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));
1276 // Decide whether to enable caching
1277 if ($this->cache && $parsed_feed_url['scheme'] !== '')
1279 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'));
1282 // Fetch the data via SimplePie_File into $this->raw_data
1283 if (($fetched = $this->fetch_data($cache)) === true)
1287 elseif ($fetched === false) {
1291 list($headers, $sniffed) = $fetched;
1294 // Set up array of possible encodings
1295 $encodings = array();
1297 // First check to see if input has been overridden.
1298 if ($this->input_encoding !== false)
1300 $encodings[] = $this->input_encoding;
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');
1306 // RFC 3023 (only applies to sniffed content)
1307 if (isset($sniffed))
1309 if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
1311 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1313 $encodings[] = strtoupper($charset[1]);
1315 $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
1316 $encodings[] = 'UTF-8';
1318 elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
1320 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1322 $encodings[] = $charset[1];
1324 $encodings[] = 'US-ASCII';
1326 // Text MIME-type default
1327 elseif (substr($sniffed, 0, 5) === 'text/')
1329 $encodings[] = 'US-ASCII';
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';
1338 // There's no point in trying an encoding twice
1339 $encodings = array_unique($encodings);
1341 // Loop through each possible encoding, till we return something, or run out of possibilities
1342 foreach ($encodings as $encoding)
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')))
1347 // Create new parser
1348 $parser = $this->registry->create('Parser');
1350 // If it's parsed fine
1351 if ($parser->parse($utf8_data, 'UTF-8'))
1353 $this->data = $parser->get_data();
1354 if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
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__));
1361 if (isset($headers))
1363 $this->data['headers'] = $headers;
1365 $this->data['build'] = SIMPLEPIE_BUILD;
1367 // Cache the file if caching is enabled
1368 if ($cache && !$cache->save($this))
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);
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());
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.';
1387 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1393 * Fetch the data via SimplePie_File
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
1399 protected function fetch_data(&$cache)
1401 // If it's enabled, use the cache
1405 $this->data = $cache->load();
1406 if (!empty($this->data))
1408 // If the cache is for an outdated build of SimplePie
1409 if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
1412 $this->data = array();
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)
1418 $this->data = array();
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']))
1423 // If the autodiscovery cache is still valid use it.
1424 if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
1426 // Do not need to do feed autodiscovery yet.
1427 if ($this->data['feed_url'] !== $this->data['url'])
1429 $this->set_feed_url($this->data['feed_url']);
1430 return $this->init();
1434 $this->data = array();
1437 // Check if the cache has been updated
1438 elseif ($cache->mtime() + $this->cache_duration < time())
1440 // If we have last-modified and/or etag set
1441 if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
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',
1446 if (isset($this->data['headers']['last-modified']))
1448 $headers['if-modified-since'] = $this->data['headers']['last-modified'];
1450 if (isset($this->data['headers']['etag']))
1452 $headers['if-none-match'] = $this->data['headers']['etag'];
1455 $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
1459 if ($file->status_code === 304)
1471 // If the cache is still valid, just return true
1474 $this->raw_data = false;
1478 // If the cache is empty, delete it
1482 $this->data = array();
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.
1488 if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url)
1490 $file =& $this->file;
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',
1497 $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen));
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)))
1503 $this->error = $file->error;
1504 return !empty($this->data);
1507 if (!$this->force_feed)
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));
1512 if (!$locate->is_feed($file))
1514 // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
1518 if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)))
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__));
1525 catch (SimplePie_Exception $e)
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()));
1534 $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
1535 if (!$cache->save($this))
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);
1539 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'));
1541 $this->feed_url = $file->url;
1546 $this->raw_data = $file->body;
1548 $headers = $file->headers;
1549 $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
1550 $sniffed = $sniffer->get_type();
1552 return array($headers, $sniffed);
1556 * Get the error message for the occured error
1558 * @return string|array Error message, or array of messages for multifeeds
1560 public function error()
1562 return $this->error;
1568 * This is the same as the old `$feed->enable_xml_dump(true)`, but returns
1569 * the data instead of printing it.
1571 * @return string|boolean Raw XML data, false if the cache is used
1573 public function get_raw_data()
1575 return $this->raw_data;
1579 * Get the character encoding used for output
1581 * @since Preview Release
1584 public function get_encoding()
1586 return $this->sanitize->output_encoding;
1590 * Send the content-type header with correct encoding
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).
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.
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
1606 * @param string $mime MIME type to serve the page as
1608 public function handle_content_type($mime = 'text/html')
1610 if (!headers_sent())
1612 $header = "Content-type: $mime;";
1613 if ($this->get_encoding())
1615 $header .= ' charset=' . $this->get_encoding();
1619 $header .= ' charset=UTF-8';
1626 * Get the type of the feed
1628 * This returns a SIMPLEPIE_TYPE_* constant, which can be tested against
1629 * using {@link http://php.net/language.operators.bitwise bitwise operators}
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
1651 public function get_type()
1653 if (!isset($this->data['type']))
1655 $this->data['type'] = SIMPLEPIE_TYPE_ALL;
1656 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
1658 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
1660 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
1662 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
1664 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
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']))
1671 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
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']))
1678 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
1681 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
1683 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
1684 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1686 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
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']))
1692 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1695 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
1699 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
1706 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
1710 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
1714 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
1718 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
1725 $this->data['type'] = SIMPLEPIE_TYPE_NONE;
1728 return $this->data['type'];
1732 * Get the URL for the feed
1734 * May or may not be different from the URL passed to {@see set_feed_url()},
1735 * depending on whether auto-discovery was used.
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
1743 public function subscribe_url()
1745 if ($this->feed_url !== null)
1747 return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
1756 * Get data for an feed-level element
1758 * This method allows you to get access to ANY element/attribute that is a
1759 * sub-element of the opening feed tag.
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
1771 * // This is probably a bad example because we already support
1772 * // <media:content> natively, but it shows you how to parse through
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'];
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
1786 public function get_feed_tags($namespace, $tag)
1788 $type = $this->get_type();
1789 if ($type & SIMPLEPIE_TYPE_ATOM_10)
1791 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
1793 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
1796 if ($type & SIMPLEPIE_TYPE_ATOM_03)
1798 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
1800 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
1803 if ($type & SIMPLEPIE_TYPE_RSS_RDF)
1805 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
1807 return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
1810 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1812 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
1814 return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
1821 * Get data for an channel-level element
1823 * This method allows you to get access to ANY element/attribute in the
1824 * channel/header section of the feed.
1826 * See {@see SimplePie::get_feed_tags()} for a description of the return value
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
1834 public function get_channel_tags($namespace, $tag)
1836 $type = $this->get_type();
1837 if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
1839 if ($return = $this->get_feed_tags($namespace, $tag))
1844 if ($type & SIMPLEPIE_TYPE_RSS_10)
1846 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
1848 if (isset($channel[0]['child'][$namespace][$tag]))
1850 return $channel[0]['child'][$namespace][$tag];
1854 if ($type & SIMPLEPIE_TYPE_RSS_090)
1856 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
1858 if (isset($channel[0]['child'][$namespace][$tag]))
1860 return $channel[0]['child'][$namespace][$tag];
1864 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1866 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
1868 if (isset($channel[0]['child'][$namespace][$tag]))
1870 return $channel[0]['child'][$namespace][$tag];
1878 * Get data for an channel-level element
1880 * This method allows you to get access to ANY element/attribute in the
1881 * image/logo section of the feed.
1883 * See {@see SimplePie::get_feed_tags()} for a description of the return value
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
1891 public function get_image_tags($namespace, $tag)
1893 $type = $this->get_type();
1894 if ($type & SIMPLEPIE_TYPE_RSS_10)
1896 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
1898 if (isset($image[0]['child'][$namespace][$tag]))
1900 return $image[0]['child'][$namespace][$tag];
1904 if ($type & SIMPLEPIE_TYPE_RSS_090)
1906 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
1908 if (isset($image[0]['child'][$namespace][$tag]))
1910 return $image[0]['child'][$namespace][$tag];
1914 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1916 if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
1918 if (isset($image[0]['child'][$namespace][$tag]))
1920 return $image[0]['child'][$namespace][$tag];
1928 * Get the base URL value from the feed
1930 * Uses `<xml:base>` if available, otherwise uses the first link in the
1931 * feed, or failing that, the URL of the feed itself.
1934 * @see subscribe_url
1936 * @param array $element
1939 public function get_base($element = array())
1941 if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
1943 return $element['xml_base'];
1945 elseif ($this->get_link() !== null)
1947 return $this->get_link();
1951 return $this->subscribe_url();
1956 * Sanitize feed data
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
1965 public function sanitize($data, $type, $base = '')
1967 return $this->sanitize->sanitize($data, $type, $base);
1971 * Get the title of the feed
1973 * Uses `<atom:title>`, `<title>` or `<dc:title>`
1975 * @since 1.0 (previously called `get_feed_title` since 0.8)
1976 * @return string|null
1978 public function get_title()
1980 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
1982 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1984 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
1986 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1988 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
1990 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1992 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
1994 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1996 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
1998 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2000 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2002 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2004 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2006 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2015 * Get a category for the feed
2018 * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
2019 * @return SimplePie_Category|null
2021 public function get_category($key = 0)
2023 $categories = $this->get_categories();
2024 if (isset($categories[$key]))
2026 return $categories[$key];
2035 * Get all categories for the feed
2037 * Uses `<atom:category>`, `<category>` or `<dc:subject>`
2040 * @return array|null List of {@see SimplePie_Category} objects
2042 public function get_categories()
2044 $categories = array();
2046 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
2051 if (isset($category['attribs']['']['term']))
2053 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
2055 if (isset($category['attribs']['']['scheme']))
2057 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2059 if (isset($category['attribs']['']['label']))
2061 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
2063 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
2065 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
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']))
2072 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
2078 $categories[] = $this->registry->create('Category', array($term, $scheme, null));
2080 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
2082 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2084 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
2086 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2089 if (!empty($categories))
2091 return array_unique($categories);
2100 * Get an author for the feed
2103 * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
2104 * @return SimplePie_Author|null
2106 public function get_author($key = 0)
2108 $authors = $this->get_authors();
2109 if (isset($authors[$key]))
2111 return $authors[$key];
2120 * Get all authors for the feed
2122 * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
2125 * @return array|null List of {@see SimplePie_Author} objects
2127 public function get_authors()
2130 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
2135 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2137 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2139 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
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]));
2143 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2145 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2147 if ($name !== null || $email !== null || $uri !== null)
2149 $authors[] = $this->registry->create('Author', array($name, $uri, $email));
2152 if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
2157 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2159 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2161 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
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]));
2165 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2167 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2169 if ($name !== null || $email !== null || $url !== null)
2171 $authors[] = $this->registry->create('Author', array($name, $url, $email));
2174 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
2176 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2178 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
2180 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2182 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
2184 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2187 if (!empty($authors))
2189 return array_unique($authors);
2198 * Get a contributor for the feed
2201 * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
2202 * @return SimplePie_Author|null
2204 public function get_contributor($key = 0)
2206 $contributors = $this->get_contributors();
2207 if (isset($contributors[$key]))
2209 return $contributors[$key];
2218 * Get all contributors for the feed
2220 * Uses `<atom:contributor>`
2223 * @return array|null List of {@see SimplePie_Author} objects
2225 public function get_contributors()
2227 $contributors = array();
2228 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
2233 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2235 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2237 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
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]));
2241 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2243 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2245 if ($name !== null || $email !== null || $uri !== null)
2247 $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
2250 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
2255 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2257 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2259 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
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]));
2263 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2265 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2267 if ($name !== null || $email !== null || $url !== null)
2269 $contributors[] = $this->registry->create('Author', array($name, $url, $email));
2273 if (!empty($contributors))
2275 return array_unique($contributors);
2284 * Get a single link for the feed
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
2291 public function get_link($key = 0, $rel = 'alternate')
2293 $links = $this->get_links($rel);
2294 if (isset($links[$key]))
2296 return $links[$key];
2305 * Get the permalink for the item
2307 * Returns the first link available with a relationship of "alternate".
2308 * Identical to {@see get_link()} with key 0
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
2315 public function get_permalink()
2317 return $this->get_link(0);
2321 * Get all links for the feed
2323 * Uses `<atom:link>` or `<link>`
2326 * @param string $rel The relationship of links to return
2327 * @return array|null Links found for the feed (strings)
2329 public function get_links($rel = 'alternate')
2331 if (!isset($this->data['links']))
2333 $this->data['links'] = array();
2334 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
2336 foreach ($links as $link)
2338 if (isset($link['attribs']['']['href']))
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));
2345 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
2347 foreach ($links as $link)
2349 if (isset($link['attribs']['']['href']))
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));
2357 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2359 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2361 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2363 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2365 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2367 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2370 $keys = array_keys($this->data['links']);
2371 foreach ($keys as $key)
2373 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
2375 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
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];
2382 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
2385 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
2387 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
2389 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
2393 if (isset($this->data['links'][$rel]))
2395 return $this->data['links'][$rel];
2403 public function get_all_discovered_feeds()
2405 return $this->all_discovered_feeds;
2409 * Get the content for the item
2411 * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`,
2412 * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>`
2414 * @since 1.0 (previously called `get_feed_description()` since 0.8)
2415 * @return string|null
2417 public function get_description()
2419 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
2421 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2423 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
2425 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2427 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
2429 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2431 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
2433 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2435 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
2437 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2439 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
2441 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2443 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
2445 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2447 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
2449 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2451 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
2453 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2462 * Get the copyright info for the feed
2464 * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>`
2466 * @since 1.0 (previously called `get_feed_copyright()` since 0.8)
2467 * @return string|null
2469 public function get_copyright()
2471 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
2473 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2475 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
2477 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2479 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
2481 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2483 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
2485 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2487 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
2489 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2498 * Get the language for the feed
2500 * Uses `<language>`, `<dc:language>`, or @xml_lang
2502 * @since 1.0 (previously called `get_feed_language()` since 0.8)
2503 * @return string|null
2505 public function get_language()
2507 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
2509 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2511 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
2513 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2515 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
2517 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2519 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
2521 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2523 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
2525 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2527 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
2529 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2531 elseif (isset($this->data['headers']['content-language']))
2533 return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
2542 * Get the latitude coordinates for the item
2544 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2546 * Uses `<geo:lat>` or `<georss:point>`
2549 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2550 * @link http://www.georss.org/ GeoRSS
2551 * @return string|null
2553 public function get_latitude()
2556 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
2558 return (float) $return[0]['data'];
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))
2562 return (float) $match[1];
2571 * Get the longitude coordinates for the feed
2573 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2575 * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
2578 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2579 * @link http://www.georss.org/ GeoRSS
2580 * @return string|null
2582 public function get_longitude()
2584 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
2586 return (float) $return[0]['data'];
2588 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
2590 return (float) $return[0]['data'];
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))
2594 return (float) $match[2];
2603 * Get the feed logo's title
2605 * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title.
2607 * Uses `<image><title>` or `<image><dc:title>`
2609 * @return string|null
2611 public function get_image_title()
2613 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2615 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2617 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2619 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2621 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
2623 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2625 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2627 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2629 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2631 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2640 * Get the feed logo's URL
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.
2645 * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
2646 * `<image><title>` or `<image><dc:title>`
2648 * @return string|null
2650 public function get_image_url()
2652 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
2654 return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
2656 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
2658 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2660 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
2662 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2664 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
2666 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2668 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
2670 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2672 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2674 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2683 * Get the feed logo's link
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.
2688 * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
2689 * `<image><title>` or `<image><dc:title>`
2691 * @return string|null
2693 public function get_image_link()
2695 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2697 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2699 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2701 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2703 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2705 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2714 * Get the feed logo's link
2716 * RSS 2.0 feeds are allowed to have a "feed logo" width.
2718 * Uses `<image><width>` or defaults to 88.0 if no width is specified and
2719 * the feed is an RSS 2.0 feed.
2721 * @return int|float|null
2723 public function get_image_width()
2725 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
2727 return round($return[0]['data']);
2729 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2740 * Get the feed logo's height
2742 * RSS 2.0 feeds are allowed to have a "feed logo" height.
2744 * Uses `<image><height>` or defaults to 31.0 if no height is specified and
2745 * the feed is an RSS 2.0 feed.
2747 * @return int|float|null
2749 public function get_image_height()
2751 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
2753 return round($return[0]['data']);
2755 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2766 * Get the number of items in the feed
2768 * This is well-suited for {@link http://php.net/for for()} loops with
2771 * @param int $max Maximum value to return. 0 for no limit
2772 * @return int Number of items in the feed
2774 public function get_item_quantity($max = 0)
2777 $qty = count($this->get_items());
2784 return ($qty > $max) ? $max : $qty;
2789 * Get a single item from the feed
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.
2795 * @see get_item_quantity()
2797 * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1
2798 * @return SimplePie_Item|null
2800 public function get_item($key = 0)
2802 $items = $this->get_items();
2803 if (isset($items[$key]))
2805 return $items[$key];
2814 * Get all items from the feed
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.
2820 * @see get_item_quantity
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
2826 public function get_items($start = 0, $end = 0)
2828 if (!isset($this->data['items']))
2830 if (!empty($this->multifeed_objects))
2832 $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
2836 $this->data['items'] = array();
2837 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
2839 $keys = array_keys($items);
2840 foreach ($keys as $key)
2842 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2845 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
2847 $keys = array_keys($items);
2848 foreach ($keys as $key)
2850 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2853 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
2855 $keys = array_keys($items);
2856 foreach ($keys as $key)
2858 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2861 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
2863 $keys = array_keys($items);
2864 foreach ($keys as $key)
2866 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2869 if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
2871 $keys = array_keys($items);
2872 foreach ($keys as $key)
2874 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2880 if (!empty($this->data['items']))
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))
2885 if (!isset($this->data['ordered_items']))
2888 foreach ($this->data['items'] as $item)
2890 if (!$item->get_date('U'))
2897 $this->data['ordered_items'] = $this->data['items'];
2900 usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
2903 $items = $this->data['ordered_items'];
2907 $items = $this->data['items'];
2910 // Slice the data as desired
2913 return array_slice($items, $start);
2917 return array_slice($items, $start, $end);
2927 * Set the favicon handler
2929 * @deprecated Use your own favicon handling instead
2931 public function set_favicon_handler($page = false, $qs = 'i')
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);
2939 * Get the favicon for the current feed
2941 * @deprecated Use your own favicon handling instead
2943 public function get_favicon()
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);
2948 if (($url = $this->get_link()) !== null)
2950 return 'http://g.etfv.co/' . urlencode($url);
2957 * Magic method handler
2959 * @param string $method Method name
2960 * @param array $args Arguments to the method
2963 public function __call($method, $args)
2965 if (strpos($method, 'subscribe_') === 0)
2967 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
2968 trigger_error('subscribe_*() has been deprecated, implement the callback yourself', $level);
2971 if ($method === 'enable_xml_dump')
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);
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);
2986 * Sorting callback for items
2989 * @param SimplePie $a
2990 * @param SimplePie $b
2993 public static function sort_items($a, $b)
2995 return $a->get_date('U') <= $b->get_date('U');
2999 * Merge items from several feeds into one
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.
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
3011 public static function merge_items($urls, $start = 0, $end = 0, $limit = 0)
3013 if (is_array($urls) && sizeof($urls) > 0)
3016 foreach ($urls as $arg)
3018 if ($arg instanceof SimplePie)
3020 $items = array_merge($items, $arg->get_items(0, $limit));
3024 trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
3029 foreach ($items as $item)
3031 if (!$item->get_date('U'))
3040 usort($items, array(get_class($urls[0]), 'sort_items'));
3045 return array_slice($items, $start);
3049 return array_slice($items, $start, $end);
3054 trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
3061 * Manages all author-related data
3063 * Used by {@see SimplePie_Item::get_author()} and {@see SimplePie::get_authors()}
3065 * This class can be overloaded with {@see SimplePie::set_author_class()}
3067 * @package SimplePie
3070 class SimplePie_Author
3089 * Author's email address
3097 * Constructor, used to input the data
3099 * @param string $name
3100 * @param string $link
3101 * @param string $email
3103 public function __construct($name = null, $link = null, $email = null)
3105 $this->name = $name;
3106 $this->link = $link;
3107 $this->email = $email;
3111 * String-ified version
3115 public function __toString()
3117 // There is no $this->data here
3118 return md5(serialize($this));
3124 * @return string|null
3126 public function get_name()
3128 if ($this->name !== null)
3141 * @return string|null
3143 public function get_link()
3145 if ($this->link !== null)
3156 * Author's email address
3158 * @return string|null
3160 public function get_email()
3162 if ($this->email !== null)
3164 return $this->email;
3174 * Base for cache objects
3176 * Classes to be used with {@see SimplePie_Cache::register()} are expected
3177 * to implement this interface.
3179 * @package SimplePie
3180 * @subpackage Caching
3182 interface SimplePie_Cache_Base
3189 const TYPE_FEED = 'spc';
3196 const TYPE_IMAGE = 'spi';
3199 * Create a new cache object
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
3205 public function __construct($location, $name, $type);
3208 * Save data to the cache
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
3213 public function save($data);
3216 * Retrieve the data saved to the cache
3218 * @return array Data for SimplePie::$data
3220 public function load();
3223 * Retrieve the last modified time for the cache
3225 * @return int Timestamp
3227 public function mtime();
3230 * Set the last modified time to the current time
3232 * @return bool Success status
3234 public function touch();
3239 * @return bool Success status
3241 public function unlink();
3245 * Base class for database-based caches
3247 * @package SimplePie
3248 * @subpackage Caching
3250 abstract class SimplePie_Cache_DB implements SimplePie_Cache_Base
3253 * Helper for database conversion
3255 * Converts a given {@see SimplePie} object into data to be stored
3257 * @param SimplePie $data
3258 * @return array First item is the serialized data for storage, second item is the unique ID for this item
3260 protected static function prepare_simplepie_object_for_cache($data)
3262 $items = $data->get_items();
3263 $items_by_id = array();
3267 foreach ($items as $item)
3269 $items_by_id[$item->get_id()] = $item;
3272 if (count($items_by_id) !== count($items))
3274 $items_by_id = array();
3275 foreach ($items as $item)
3277 $items_by_id[$item->get_id(true)] = $item;
3281 if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
3283 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
3285 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
3287 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
3289 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
3291 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
3293 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
3295 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
3302 if ($channel !== null)
3304 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
3306 unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
3308 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
3310 unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
3312 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
3314 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
3316 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
3318 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
3320 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
3322 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
3325 if (isset($data->data['items']))
3327 unset($data->data['items']);
3329 if (isset($data->data['ordered_items']))
3331 unset($data->data['ordered_items']);
3334 return array(serialize($data->data), $items_by_id);
3339 * Caches data to the filesystem
3341 * @package SimplePie
3342 * @subpackage Caching
3344 class SimplePie_Cache_File implements SimplePie_Cache_Base
3349 * @see SimplePie::$cache_location
3352 protected $location;
3359 protected $filename;
3366 protected $extension;
3376 * Create a new cache object
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
3382 public function __construct($location, $name, $type)
3384 $this->location = $location;
3385 $this->filename = $name;
3386 $this->extension = $type;
3387 $this->name = "$this->location/$this->filename.$this->extension";
3391 * Save data to the cache
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
3396 public function save($data)
3398 if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
3400 if ($data instanceof SimplePie)
3402 $data = $data->data;
3405 $data = serialize($data);
3406 return (bool) file_put_contents($this->name, $data);
3412 * Retrieve the data saved to the cache
3414 * @return array Data for SimplePie::$data
3416 public function load()
3418 if (file_exists($this->name) && is_readable($this->name))
3420 return unserialize(file_get_contents($this->name));
3426 * Retrieve the last modified time for the cache
3428 * @return int Timestamp
3430 public function mtime()
3432 if (file_exists($this->name))
3434 return filemtime($this->name);
3440 * Set the last modified time to the current time
3442 * @return bool Success status
3444 public function touch()
3446 if (file_exists($this->name))
3448 return touch($this->name);
3456 * @return bool Success status
3458 public function unlink()
3460 if (file_exists($this->name))
3462 return unlink($this->name);
3469 * Caches data to memcache
3471 * Registered for URLs with the "memcache" protocol
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
3477 * @package SimplePie
3478 * @subpackage Caching
3481 class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
3505 * Create a new cache object
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
3511 public function __construct($location, $name, $type)
3513 $this->options = array(
3514 'host' => '127.0.0.1',
3517 'timeout' => 3600, // one hour
3518 'prefix' => 'simplepie_',
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");
3527 $this->cache = new Memcache();
3528 $this->cache->addServer($this->options['host'], (int) $this->options['port']);
3532 * Save data to the cache
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
3537 public function save($data)
3539 if ($data instanceof SimplePie)
3541 $data = $data->data;
3543 return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
3547 * Retrieve the data saved to the cache
3549 * @return array Data for SimplePie::$data
3551 public function load()
3553 $data = $this->cache->get($this->name);
3555 if ($data !== false)
3557 return unserialize($data);
3563 * Retrieve the last modified time for the cache
3565 * @return int Timestamp
3567 public function mtime()
3569 $data = $this->cache->get($this->name);
3571 if ($data !== false)
3573 // essentially ignore the mtime because Memcache expires on it's own
3581 * Set the last modified time to the current time
3583 * @return bool Success status
3585 public function touch()
3587 $data = $this->cache->get($this->name);
3589 if ($data !== false)
3591 return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
3600 * @return bool Success status
3602 public function unlink()
3604 return $this->cache->delete($this->name, 0);
3609 * Caches data to a MySQL database
3611 * Registered for URLs with the "mysql" protocol
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_`
3617 * @package SimplePie
3618 * @subpackage Caching
3620 class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
3644 * Create a new cache object
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
3650 public function __construct($location, $name, $type)
3652 $this->options = array(
3655 'host' => '127.0.0.1',
3662 $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
3664 // Path is prefixed with a "/"
3665 $this->options['dbname'] = substr($this->options['path'], 1);
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'));
3671 catch (PDOException $e)
3673 $this->mysql = null;
3677 $this->id = $name . $type;
3679 if (!$query = $this->mysql->query('SHOW TABLES'))
3681 $this->mysql = null;
3686 while ($row = $query->fetchColumn())
3691 if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
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)
3696 $this->mysql = null;
3700 if (!in_array($this->options['extras']['prefix'] . 'items', $db))
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)
3705 $this->mysql = null;
3711 * Save data to the cache
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
3716 public function save($data)
3718 if ($this->mysql === null)
3723 if ($data instanceof SimplePie)
3725 $data = clone $data;
3727 $prepared = self::prepare_simplepie_object_for_cache($data);
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())
3733 if ($query->fetchColumn() > 0)
3735 $items = count($prepared[1]);
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);
3744 $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
3745 $query = $this->mysql->prepare($sql);
3748 $query->bindValue(':data', $prepared[0]);
3749 $query->bindValue(':time', time());
3750 $query->bindValue(':feed', $this->id);
3751 if (!$query->execute())
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())
3769 $ids = array_keys($prepared[1]);
3772 foreach ($ids as $id)
3774 $database_ids[] = $this->mysql->quote($id);
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);
3780 if ($query->execute())
3782 $existing_ids = array();
3783 while ($row = $query->fetchColumn())
3785 $existing_ids[] = $row;
3788 $new_ids = array_diff($ids, $existing_ids);
3790 foreach ($new_ids as $new_id)
3792 if (!($date = $prepared[1][$new_id]->get_date('U')))
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())
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())
3822 if ($query->rowCount() > 0)
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())
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())
3850 * Retrieve the data saved to the cache
3852 * @return array Data for SimplePie::$data
3854 public function load()
3856 if ($this->mysql === null)
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()))
3865 $data = unserialize($row[1]);
3867 if (isset($this->options['items'][0]))
3869 $items = (int) $this->options['items'][0];
3873 $items = (int) $row[0];
3878 if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
3880 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
3882 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
3884 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
3886 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
3888 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
3890 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
3892 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
3901 $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
3904 $sql .= ' LIMIT ' . $items;
3907 $query = $this->mysql->prepare($sql);
3908 $query->bindValue(':feed', $this->id);
3909 if ($query->execute())
3911 while ($row = $query->fetchColumn())
3913 $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
3928 * Retrieve the last modified time for the cache
3930 * @return int Timestamp
3932 public function mtime()
3934 if ($this->mysql === null)
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()))
3952 * Set the last modified time to the current time
3954 * @return bool Success status
3956 public function touch()
3958 if ($this->mysql === null)
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)
3979 * @return bool Success status
3981 public function unlink()
3983 if ($this->mysql === null)
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())
4004 * Used to create cache objects
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()}
4010 * @package SimplePie
4011 * @subpackage Caching
4013 class SimplePie_Cache
4016 * Cache handler classes
4018 * These receive 3 parameters to their constructor, as documented in
4022 protected static $handlers = array(
4023 'mysql' => 'SimplePie_Cache_MySQL',
4024 'memcache' => 'SimplePie_Cache_Memcache',
4028 * Don't call the constructor. Please.
4030 private function __construct() { }
4033 * Create a new SimplePie_Cache object
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`
4040 public static function get_handler($location, $filename, $extension)
4042 $type = explode(':', $location, 2);
4044 if (!empty(self::$handlers[$type]))
4046 $class = self::$handlers[$type];
4047 return new $class($location, $filename, $extension);
4050 return new SimplePie_Cache_File($location, $filename, $extension);
4054 * Create a new SimplePie_Cache object
4056 * @deprecated Use {@see get_handler} instead
4058 public function create($location, $filename, $extension)
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);
4065 * Register a handler
4067 * @param string $type DSN type to register for
4068 * @param string $class Name of handler class. Must implement SimplePie_Cache_Base
4070 public static function register($type, $class)
4072 self::$handlers[$type] = $class;
4076 * Parse a URL into an array
4078 * @param string $url
4081 public static function parse_URL($url)
4083 $params = parse_url($url);
4084 $params['extras'] = array();
4085 if (isset($params['query']))
4087 parse_str($params['query'], $params['extras']);
4094 * Handles `<media:text>` captions as defined in Media RSS.
4096 * Used by {@see SimplePie_Enclosure::get_caption()} and {@see SimplePie_Enclosure::get_captions()}
4098 * This class can be overloaded with {@see SimplePie::set_caption_class()}
4100 * @package SimplePie
4103 class SimplePie_Caption
4117 * @see get_language()
4125 * @see get_starttime()
4133 * @see get_endtime()
4146 * Constructor, used to input the data
4148 * For documentation on all the parameters, see the corresponding
4149 * properties and their accessors
4151 public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
4153 $this->type = $type;
4154 $this->lang = $lang;
4155 $this->startTime = $startTime;
4156 $this->endTime = $endTime;
4157 $this->text = $text;
4161 * String-ified version
4165 public function __toString()
4167 // There is no $this->data here
4168 return md5(serialize($this));
4174 * @return string|null Time in the format 'hh:mm:ss.SSS'
4176 public function get_endtime()
4178 if ($this->endTime !== null)
4180 return $this->endTime;
4191 * @link http://tools.ietf.org/html/rfc3066
4192 * @return string|null Language code as per RFC 3066
4194 public function get_language()
4196 if ($this->lang !== null)
4207 * Get the start time
4209 * @return string|null Time in the format 'hh:mm:ss.SSS'
4211 public function get_starttime()
4213 if ($this->startTime !== null)
4215 return $this->startTime;
4224 * Get the text of the caption
4226 * @return string|null
4228 public function get_text()
4230 if ($this->text !== null)
4241 * Get the content type (not MIME type)
4243 * @return string|null Either 'text' or 'html'
4245 public function get_type()
4247 if ($this->type !== null)
4259 * Manages all category-related data
4261 * Used by {@see SimplePie_Item::get_category()} and {@see SimplePie_Item::get_categories()}
4263 * This class can be overloaded with {@see SimplePie::set_category_class()}
4265 * @package SimplePie
4268 class SimplePie_Category
4271 * Category identifier
4279 * Categorization scheme identifier
4287 * Human readable label
4295 * Constructor, used to input the data
4297 * @param string $term
4298 * @param string $scheme
4299 * @param string $label
4301 public function __construct($term = null, $scheme = null, $label = null)
4303 $this->term = $term;
4304 $this->scheme = $scheme;
4305 $this->label = $label;
4309 * String-ified version
4313 public function __toString()
4315 // There is no $this->data here
4316 return md5(serialize($this));
4320 * Get the category identifier
4322 * @return string|null
4324 public function get_term()
4326 if ($this->term !== null)
4337 * Get the categorization scheme identifier
4339 * @return string|null
4341 public function get_scheme()
4343 if ($this->scheme !== null)
4345 return $this->scheme;
4354 * Get the human readable label
4356 * @return string|null
4358 public function get_label()
4360 if ($this->label !== null)
4362 return $this->label;
4366 return $this->get_term();
4372 * Content-type sniffing
4374 * Based on the rules in http://tools.ietf.org/html/draft-abarth-mime-sniff-06
4376 * This is used since we can't always trust Content-Type headers, and is based
4377 * upon the HTML5 parsing rules.
4380 * This class can be overloaded with {@see SimplePie::set_content_type_sniffer_class()}
4382 * @package SimplePie
4385 class SimplePie_Content_Type_Sniffer
4390 * @var SimplePie_File
4395 * Create an instance of the class with the input file
4397 * @param SimplePie_Content_Type_Sniffer $file Input file
4399 public function __construct($file)
4401 $this->file = $file;
4405 * Get the Content-Type of the specified file
4407 * @return string Actual Content-Type
4409 public function get_type()
4411 if (isset($this->file->headers['content-type']))
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'))
4419 return $this->text_or_binary();
4422 if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
4424 $official = substr($this->file->headers['content-type'], 0, $pos);
4428 $official = $this->file->headers['content-type'];
4430 $official = trim(strtolower($official));
4432 if ($official === 'unknown/unknown'
4433 || $official === 'application/unknown')
4435 return $this->unknown();
4437 elseif (substr($official, -4) === '+xml'
4438 || $official === 'text/xml'
4439 || $official === 'application/xml')
4443 elseif (substr($official, 0, 6) === 'image/')
4445 if ($return = $this->image())
4454 elseif ($official === 'text/html')
4456 return $this->feed_or_html();
4465 return $this->unknown();
4470 * Sniff text or binary
4472 * @return string Actual Content-Type
4474 public function text_or_binary()
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")
4481 return 'text/plain';
4483 elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
4485 return 'application/octect-stream';
4489 return 'text/plain';
4496 * @return string Actual Content-Type
4498 public function unknown()
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')
4507 elseif (substr($this->file->body, 0, 5) === '%PDF-')
4509 return 'application/pdf';
4511 elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
4513 return 'application/postscript';
4515 elseif (substr($this->file->body, 0, 6) === 'GIF87a'
4516 || substr($this->file->body, 0, 6) === 'GIF89a')
4520 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
4524 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
4526 return 'image/jpeg';
4528 elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
4532 elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
4534 return 'image/vnd.microsoft.icon';
4538 return $this->text_or_binary();
4545 * @return string Actual Content-Type
4547 public function image()
4549 if (substr($this->file->body, 0, 6) === 'GIF87a'
4550 || substr($this->file->body, 0, 6) === 'GIF89a')
4554 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
4558 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
4560 return 'image/jpeg';
4562 elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
4566 elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
4568 return 'image/vnd.microsoft.icon';
4579 * @return string Actual Content-Type
4581 public function feed_or_html()
4583 $len = strlen($this->file->body);
4584 $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
4588 switch ($this->file->body[$pos])
4594 $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
4605 if (substr($this->file->body, $pos, 3) === '!--')
4608 if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
4617 elseif (substr($this->file->body, $pos, 1) === '!')
4619 if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
4628 elseif (substr($this->file->body, $pos, 1) === '?')
4630 if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
4639 elseif (substr($this->file->body, $pos, 3) === 'rss'
4640 || substr($this->file->body, $pos, 7) === 'rdf:RDF')
4642 return 'application/rss+xml';
4644 elseif (substr($this->file->body, $pos, 4) === 'feed')
4646 return 'application/atom+xml';
4659 * Manages `<media:copyright>` copyright tags as defined in Media RSS
4661 * Used by {@see SimplePie_Enclosure::get_copyright()}
4663 * This class can be overloaded with {@see SimplePie::set_copyright_class()}
4665 * @package SimplePie
4668 class SimplePie_Copyright
4682 * @see get_attribution()
4687 * Constructor, used to input the data
4689 * For documentation on all the parameters, see the corresponding
4690 * properties and their accessors
4692 public function __construct($url = null, $label = null)
4695 $this->label = $label;
4699 * String-ified version
4703 public function __toString()
4705 // There is no $this->data here
4706 return md5(serialize($this));
4710 * Get the copyright URL
4712 * @return string|null URL to copyright information
4714 public function get_url()
4716 if ($this->url !== null)
4727 * Get the attribution text
4729 * @return string|null
4731 public function get_attribution()
4733 if ($this->label !== null)
4735 return $this->label;
4747 * Class for backward compatibility.
4749 * @deprecated Use {@see SimplePie} directly
4750 * @package SimplePie
4753 class SimplePie_Core extends SimplePie
4759 * Handles `<media:credit>` as defined in Media RSS
4761 * Used by {@see SimplePie_Enclosure::get_credit()} and {@see SimplePie_Enclosure::get_credits()}
4763 * This class can be overloaded with {@see SimplePie::set_credit_class()}
4765 * @package SimplePie
4768 class SimplePie_Credit
4779 * Organizational scheme
4795 * Constructor, used to input the data
4797 * For documentation on all the parameters, see the corresponding
4798 * properties and their accessors
4800 public function __construct($role = null, $scheme = null, $name = null)
4802 $this->role = $role;
4803 $this->scheme = $scheme;
4804 $this->name = $name;
4808 * String-ified version
4812 public function __toString()
4814 // There is no $this->data here
4815 return md5(serialize($this));
4819 * Get the role of the person receiving credit
4821 * @return string|null
4823 public function get_role()
4825 if ($this->role !== null)
4836 * Get the organizational scheme
4838 * @return string|null
4840 public function get_scheme()
4842 if ($this->scheme !== null)
4844 return $this->scheme;
4853 * Get the credited person/entity's name
4855 * @return string|null
4857 public function get_name()
4859 if ($this->name !== null)
4871 * Decode HTML Entities
4873 * This implements HTML5 as of revision 967 (2007-06-28)
4875 * @deprecated Use DOMDocument instead!
4876 * @package SimplePie
4878 class SimplePie_Decode_HTML_Entities
4889 * Currently consumed bytes
4897 * Position of the current byte being parsed
4905 * Create an instance of the class with the input data
4908 * @param string $data Input data
4910 public function __construct($data)
4912 $this->data = $data;
4916 * Parse the input data
4919 * @return string Output data
4921 public function parse()
4923 while (($this->position = strpos($this->data, '&', $this->position)) !== false)
4927 $this->consumed = '';
4933 * Consume the next byte
4936 * @return mixed The next byte, or false, if there is no more data
4938 public function consume()
4940 if (isset($this->data[$this->position]))
4942 $this->consumed .= $this->data[$this->position];
4943 return $this->data[$this->position++];
4952 * Consume a range of characters
4955 * @param string $chars Characters to consume
4956 * @return mixed A series of characters that match the range, or false
4958 public function consume_range($chars)
4960 if ($len = strspn($this->data, $chars, $this->position))
4962 $data = substr($this->data, $this->position, $len);
4963 $this->consumed .= $data;
4964 $this->position += $len;
4974 * Unconsume one byte
4978 public function unconsume()
4980 $this->consumed = substr($this->consumed, 0, -1);
4989 public function entity()
4991 switch ($this->consume())
5005 switch ($this->consume())
5009 $range = '0123456789ABCDEFabcdef';
5014 $range = '0123456789';
5020 if ($codepoint = $this->consume_range($range))
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");
5026 $codepoint = hexdec($codepoint);
5030 $codepoint = intval($codepoint);
5033 if (isset($windows_1252_specials[$codepoint]))
5035 $replacement = $windows_1252_specials[$codepoint];
5039 $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
5042 if (!in_array($this->consume(), array(';', false), true))
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;
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",
5080 'and;' => "\xE2\x88\xA7",
5081 'ang;' => "\xE2\x88\xA0",
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",
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",
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",
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"
5423 for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
5425 $consumed = substr($this->consumed, 1);
5426 if (isset($entities[$consumed]))
5432 if ($match !== null)
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;
5443 * Handles everything related to enclosures (including Media RSS and iTunes RSS)
5445 * Used by {@see SimplePie_Item::get_enclosure()} and {@see SimplePie_Item::get_enclosures()}
5447 * This class can be overloaded with {@see SimplePie::set_enclosure_class()}
5449 * @package SimplePie
5452 class SimplePie_Enclosure
5456 * @see get_bitrate()
5462 * @see get_captions()
5468 * @see get_categories()
5474 * @see get_channels()
5479 * @var SimplePie_Copyright
5480 * @see get_copyright()
5486 * @see get_credits()
5492 * @see get_description()
5498 * @see get_duration()
5504 * @see get_expression()
5510 * @see get_framerate()
5516 * @see get_handler()
5540 * @see get_keywords()
5546 * @see get_language()
5576 * @see get_ratings()
5582 * @see get_restrictions()
5588 * @see get_sampling_rate()
5594 * @see get_thumbnails()
5617 * Constructor, used to input the data
5619 * For documentation on all the parameters, see the corresponding
5620 * properties and their accessors
5622 * @uses idna_convert If available, this will convert an IDN
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)
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;
5652 if (class_exists('idna_convert'))
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']);
5658 $this->handler = $this->get_handler(); // Needs to load last
5662 * String-ified version
5666 public function __toString()
5668 // There is no $this->data here
5669 return md5(serialize($this));
5675 * @return string|null
5677 public function get_bitrate()
5679 if ($this->bitrate !== null)
5681 return $this->bitrate;
5690 * Get a single caption
5693 * @return SimplePie_Caption|null
5695 public function get_caption($key = 0)
5697 $captions = $this->get_captions();
5698 if (isset($captions[$key]))
5700 return $captions[$key];
5711 * @return array|null Array of {@see SimplePie_Caption} objects
5713 public function get_captions()
5715 if ($this->captions !== null)
5717 return $this->captions;
5726 * Get a single category
5729 * @return SimplePie_Category|null
5731 public function get_category($key = 0)
5733 $categories = $this->get_categories();
5734 if (isset($categories[$key]))
5736 return $categories[$key];
5745 * Get all categories
5747 * @return array|null Array of {@see SimplePie_Category} objects
5749 public function get_categories()
5751 if ($this->categories !== null)
5753 return $this->categories;
5762 * Get the number of audio channels
5766 public function get_channels()
5768 if ($this->channels !== null)
5770 return $this->channels;
5779 * Get the copyright information
5781 * @return SimplePie_Copyright|null
5783 public function get_copyright()
5785 if ($this->copyright !== null)
5787 return $this->copyright;
5796 * Get a single credit
5799 * @return SimplePie_Credit|null
5801 public function get_credit($key = 0)
5803 $credits = $this->get_credits();
5804 if (isset($credits[$key]))
5806 return $credits[$key];
5817 * @return array|null Array of {@see SimplePie_Credit} objects
5819 public function get_credits()
5821 if ($this->credits !== null)
5823 return $this->credits;
5832 * Get the description of the enclosure
5834 * @return string|null
5836 public function get_description()
5838 if ($this->description !== null)
5840 return $this->description;
5849 * Get the duration of the enclosure
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)
5854 public function get_duration($convert = false)
5856 if ($this->duration !== null)
5860 $time = SimplePie_Misc::time_hms($this->duration);
5865 return $this->duration;
5875 * Get the expression
5877 * @return string Probably one of 'sample', 'full', 'nonstop', 'clip'. Defaults to 'full'
5879 public function get_expression()
5881 if ($this->expression !== null)
5883 return $this->expression;
5892 * Get the file extension
5894 * @return string|null
5896 public function get_extension()
5898 if ($this->link !== null)
5900 $url = SimplePie_Misc::parse_url($this->link);
5901 if ($url['path'] !== '')
5903 return pathinfo($url['path'], PATHINFO_EXTENSION);
5910 * Get the framerate (in frames-per-second)
5912 * @return string|null
5914 public function get_framerate()
5916 if ($this->framerate !== null)
5918 return $this->framerate;
5927 * Get the preferred handler
5929 * @return string|null One of 'flash', 'fmedia', 'quicktime', 'wmedia', 'mp3'
5931 public function get_handler()
5933 return $this->get_real_type(true);
5939 * @link http://www.rssboard.org/media-rss#media-hash
5941 * @return string|null Hash as per `media:hash`, prefixed with "$algo:"
5943 public function get_hash($key = 0)
5945 $hashes = $this->get_hashes();
5946 if (isset($hashes[$key]))
5948 return $hashes[$key];
5959 * @return array|null Array of strings, see {@see get_hash()}
5961 public function get_hashes()
5963 if ($this->hashes !== null)
5965 return $this->hashes;
5976 * @return string|null
5978 public function get_height()
5980 if ($this->height !== null)
5982 return $this->height;
5993 * @link http://tools.ietf.org/html/rfc3066
5994 * @return string|null Language code as per RFC 3066
5996 public function get_language()
5998 if ($this->lang !== null)
6009 * Get a single keyword
6012 * @return string|null
6014 public function get_keyword($key = 0)
6016 $keywords = $this->get_keywords();
6017 if (isset($keywords[$key]))
6019 return $keywords[$key];
6030 * @return array|null Array of strings
6032 public function get_keywords()
6034 if ($this->keywords !== null)
6036 return $this->keywords;
6047 * @return float Length in bytes
6049 public function get_length()
6051 if ($this->length !== null)
6053 return $this->length;
6064 * @return string|null
6066 public function get_link()
6068 if ($this->link !== null)
6070 return urldecode($this->link);
6081 * @link http://www.rssboard.org/media-rss#media-content
6082 * @return string|null Should be one of 'image', 'audio', 'video', 'document', 'executable'
6084 public function get_medium()
6086 if ($this->medium !== null)
6088 return $this->medium;
6097 * Get the player URL
6099 * Typically the same as {@see get_permalink()}
6100 * @return string|null Player URL
6102 public function get_player()
6104 if ($this->player !== null)
6106 return $this->player;
6115 * Get a single rating
6118 * @return SimplePie_Rating|null
6120 public function get_rating($key = 0)
6122 $ratings = $this->get_ratings();
6123 if (isset($ratings[$key]))
6125 return $ratings[$key];
6136 * @return array|null Array of {@see SimplePie_Rating} objects
6138 public function get_ratings()
6140 if ($this->ratings !== null)
6142 return $this->ratings;
6151 * Get a single restriction
6154 * @return SimplePie_Restriction|null
6156 public function get_restriction($key = 0)
6158 $restrictions = $this->get_restrictions();
6159 if (isset($restrictions[$key]))
6161 return $restrictions[$key];
6170 * Get all restrictions
6172 * @return array|null Array of {@see SimplePie_Restriction} objects
6174 public function get_restrictions()
6176 if ($this->restrictions !== null)
6178 return $this->restrictions;
6187 * Get the sampling rate (in kHz)
6189 * @return string|null
6191 public function get_sampling_rate()
6193 if ($this->samplingrate !== null)
6195 return $this->samplingrate;
6204 * Get the file size (in MiB)
6206 * @return float|null File size in mebibytes (1048 bytes)
6208 public function get_size()
6210 $length = $this->get_length();
6211 if ($length !== null)
6213 return round($length/1048576, 2);
6222 * Get a single thumbnail
6225 * @return string|null Thumbnail URL
6227 public function get_thumbnail($key = 0)
6229 $thumbnails = $this->get_thumbnails();
6230 if (isset($thumbnails[$key]))
6232 return $thumbnails[$key];
6241 * Get all thumbnails
6243 * @return array|null Array of thumbnail URLs
6245 public function get_thumbnails()
6247 if ($this->thumbnails !== null)
6249 return $this->thumbnails;
6260 * @return string|null
6262 public function get_title()
6264 if ($this->title !== null)
6266 return $this->title;
6275 * Get mimetype of the enclosure
6277 * @see get_real_type()
6278 * @return string|null MIME type
6280 public function get_type()
6282 if ($this->type !== null)
6295 * @return string|null
6297 public function get_width()
6299 if ($this->width !== null)
6301 return $this->width;
6310 * Embed the enclosure using `<embed>`
6312 * @deprecated Use the second parameter to {@see embed} instead
6314 * @param array|string $options See first paramter to {@see embed}
6315 * @return string HTML string to output
6317 public function native_embed($options='')
6319 return $this->embed($options, true);
6323 * Embed the enclosure using Javascript
6325 * `$options` is an array or comma-separated key:value string, with the
6326 * following properties:
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.
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.
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
6367 public function embed($options = '', $native = false)
6377 $bgcolor = '#ffffff';
6379 $widescreen = false;
6380 $handler = $this->get_handler();
6381 $type = $this->get_real_type();
6383 // Process options and reassign values as necessary
6384 if (is_array($options))
6390 $options = explode(',', $options);
6391 foreach($options as $option)
6393 $opt = explode(':', $option, 2);
6394 if (isset($opt[0], $opt[1]))
6396 $opt[0] = trim($opt[0]);
6397 $opt[1] = trim($opt[1]);
6413 $altclass = $opt[1];
6433 $mediaplayer = $opt[1];
6437 $widescreen = $opt[1];
6444 $mime = explode('/', $type, 2);
6447 // Process values for 'auto'
6448 if ($width === 'auto')
6450 if ($mime === 'video')
6452 if ($height === 'auto')
6456 elseif ($widescreen)
6458 $width = round((intval($height)/9)*16);
6462 $width = round((intval($height)/3)*4);
6471 if ($height === 'auto')
6473 if ($mime === 'audio')
6477 elseif ($mime === 'video')
6479 if ($width === 'auto')
6490 elseif ($widescreen)
6492 $height = round((intval($width)/16)*9);
6496 $height = round((intval($width)/4)*3);
6504 elseif ($mime === 'audio')
6509 // Set proper placeholder value
6510 if ($mime === 'audio')
6512 $placeholder = $audio;
6514 elseif ($mime === 'video')
6516 $placeholder = $video;
6522 if ($handler === 'flash')
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>";
6530 $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
6534 // Flash Media Player file types.
6535 // Preferred handler for MP3 file types.
6536 elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
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>";
6545 $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
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 === ''))
6556 if ($placeholder !== '')
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>";
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>";
6567 $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
6572 elseif ($handler === 'wmedia')
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>";
6581 $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
6586 else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
6592 * Get the real media type
6594 * Often, feeds lie to us, necessitating a bit of deeper inspection. This
6595 * converts types to their canonical representations based on the file
6599 * @param bool $find_handler Internal use only, use {@see get_handler()} instead
6600 * @return string MIME type
6602 public function get_real_type($find_handler = false)
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
6611 if ($this->get_type() !== null)
6613 $type = strtolower($this->type);
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)))
6623 switch (strtolower($this->get_extension()))
6628 $type = 'audio/acc';
6635 $type = 'audio/aiff';
6639 $type = 'audio/wav';
6646 $type = 'audio/midi';
6650 $type = 'audio/x-m4a';
6655 $type = 'audio/mp3';
6659 $type = 'audio/wav';
6663 $type = 'audio/x-ms-wax';
6667 $type = 'audio/x-ms-wma';
6673 $type = 'video/3gpp';
6678 $type = 'video/3gpp2';
6682 $type = 'video/x-ms-asf';
6686 $type = 'video/x-flv';
6700 $type = 'video/mpeg';
6704 $type = 'video/x-m4v';
6709 $type = 'video/quicktime';
6714 $type = 'video/mp4';
6718 $type = 'video/sd-video';
6722 $type = 'video/x-ms-wm';
6726 $type = 'video/x-ms-wmv';
6730 $type = 'video/x-ms-wvx';
6735 $type = 'application/futuresplash';
6739 $type = 'application/x-shockwave-flash';
6746 if (in_array($type, $types_flash))
6750 elseif (in_array($type, $types_fmedia))
6754 elseif (in_array($type, $types_quicktime))
6758 elseif (in_array($type, $types_wmedia))
6762 elseif (in_array($type, $types_mp3))
6779 * General SimplePie exception class
6781 * @package SimplePie
6783 class SimplePie_Exception extends Exception
6788 * Used for fetching remote files and reading local files
6790 * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support
6792 * This class can be overloaded with {@see SimplePie::set_file_class()}
6794 * @package SimplePie
6796 * @todo Move to properly supporting RFC2616 (HTTP/1.1)
6798 class SimplePie_File
6802 var $success = true;
6803 var $headers = array();
6808 var $method = SIMPLEPIE_FILE_SOURCE_NONE;
6810 public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
6812 if (class_exists('idna_convert'))
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']);
6819 $this->useragent = $useragent;
6820 if (preg_match('/^http(s)?:\/\//i', $url))
6822 if ($useragent === null)
6824 $useragent = ini_get('user_agent');
6825 $this->useragent = $useragent;
6827 if (!is_array($headers))
6831 if (!$force_fsockopen && function_exists('curl_exec'))
6833 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
6835 $headers2 = array();
6836 foreach ($headers as $key => $value)
6838 $headers2[] = "$key: $value";
6840 if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
6842 curl_setopt($fp, CURLOPT_ENCODING, '');
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', '>='))
6854 curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
6855 curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
6858 /* Enable Digest authentication and SSL -fox */
6859 curl_setopt($fp, CURLOPT_SSL_VERIFYPEER, false);
6860 curl_setopt($fp, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
6862 $this->headers = curl_exec($fp);
6863 if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
6865 curl_setopt($fp, CURLOPT_ENCODING, 'none');
6866 $this->headers = curl_exec($fp);
6868 if (curl_errno($fp))
6870 $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
6871 $this->success = false;
6875 $info = curl_getinfo($fp);
6877 $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
6878 $this->headers = array_pop($this->headers);
6879 $parser = new SimplePie_HTTP_Parser($this->headers);
6880 if ($parser->parse())
6882 $this->headers = $parser->headers;
6883 $this->body = $parser->body;
6884 $this->status_code = $parser->status_code;
6885 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)
6888 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
6889 return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
6896 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
6897 $url_parts = parse_url($url);
6898 $socket_host = $url_parts['host'];
6899 if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
6901 $socket_host = "ssl://$url_parts[host]";
6902 $url_parts['port'] = 443;
6904 if (!isset($url_parts['port']))
6906 $url_parts['port'] = 80;
6908 $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
6911 $this->error = 'fsockopen error: ' . $errstr;
6912 $this->success = false;
6916 stream_set_timeout($fp, $timeout);
6917 if (isset($url_parts['path']))
6919 if (isset($url_parts['query']))
6921 $get = "$url_parts[path]?$url_parts[query]";
6925 $get = $url_parts['path'];
6932 $out = "GET $get HTTP/1.1\r\n";
6933 $out .= "Host: $url_parts[host]\r\n";
6934 $out .= "User-Agent: $useragent\r\n";
6935 if (extension_loaded('zlib'))
6937 $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
6940 if (isset($url_parts['user']) && isset($url_parts['pass']))
6942 $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
6944 foreach ($headers as $key => $value)
6946 $out .= "$key: $value\r\n";
6948 $out .= "Connection: Close\r\n\r\n";
6951 $info = stream_get_meta_data($fp);
6953 $this->headers = '';
6954 while (!$info['eof'] && !$info['timed_out'])
6956 $this->headers .= fread($fp, 1160);
6957 $info = stream_get_meta_data($fp);
6959 if (!$info['timed_out'])
6961 $parser = new SimplePie_HTTP_Parser($this->headers);
6962 if ($parser->parse())
6964 $this->headers = $parser->headers;
6965 $this->body = $parser->body;
6966 $this->status_code = $parser->status_code;
6967 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)
6970 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
6971 return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
6973 if (isset($this->headers['content-encoding']))
6975 // Hey, we act dumb elsewhere, so let's do that here too
6976 switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
6980 $decoder = new SimplePie_gzdecode($this->body);
6981 if (!$decoder->parse())
6983 $this->error = 'Unable to decode HTTP "gzip" stream';
6984 $this->success = false;
6988 $this->body = $decoder->data;
6993 if (($decompressed = gzinflate($this->body)) !== false)
6995 $this->body = $decompressed;
6997 else if (($decompressed = gzuncompress($this->body)) !== false)
6999 $this->body = $decompressed;
7001 else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false)
7003 $this->body = $decompressed;
7007 $this->error = 'Unable to decode HTTP "deflate" stream';
7008 $this->success = false;
7013 $this->error = 'Unknown content coding';
7014 $this->success = false;
7021 $this->error = 'fsocket timed out';
7022 $this->success = false;
7030 $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
7031 if (!$this->body = file_get_contents($url))
7033 $this->error = 'file_get_contents could not read the file';
7034 $this->success = false;
7041 * Decode 'gzip' encoded HTTP data
7043 * @package SimplePie
7045 * @link http://www.gzip.org/format.txt
7047 class SimplePie_gzdecode
7054 * @see gzdecode::$data
7056 var $compressed_data;
7059 * Size of compressed data
7064 var $compressed_size;
7067 * Minimum size of a valid gzip string
7072 var $min_compressed_size = 18;
7075 * Current position of pointer
7094 * @see gzdecode::$compressed_data
7127 * @see gzdecode::$extra_field
7128 * @see gzdecode::$SI2
7137 * @see gzdecode::$extra_field
7138 * @see gzdecode::$SI1
7144 * Extra field content
7147 * @see gzdecode::$SI1
7148 * @see gzdecode::$SI2
7162 * Human readable comment
7170 * Don't allow anything to be set
7172 * @param string $name
7173 * @param mixed $value
7175 public function __set($name, $value)
7177 trigger_error("Cannot write property $name", E_USER_ERROR);
7181 * Set the compressed string and related properties
7183 * @param string $data
7185 public function __construct($data)
7187 $this->compressed_data = $data;
7188 $this->compressed_size = strlen($data);
7192 * Decode the GZIP stream
7194 * @return bool Successfulness
7196 public function parse()
7198 if ($this->compressed_size >= $this->min_compressed_size)
7200 // Check ID1, ID2, and CM
7201 if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
7206 // Get the FLG (FLaGs)
7207 $this->flags = ord($this->compressed_data[3]);
7209 // FLG bits above (1 << 4) are reserved
7210 if ($this->flags > 0x1F)
7215 // Advance the pointer after the above
7216 $this->position += 4;
7219 $mtime = substr($this->compressed_data, $this->position, 4);
7220 // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
7221 if (current(unpack('S', "\x00\x01")) === 1)
7223 $mtime = strrev($mtime);
7225 $this->MTIME = current(unpack('l', $mtime));
7226 $this->position += 4;
7228 // Get the XFL (eXtra FLags)
7229 $this->XFL = ord($this->compressed_data[$this->position++]);
7231 // Get the OS (Operating System)
7232 $this->OS = ord($this->compressed_data[$this->position++]);
7235 if ($this->flags & 4)
7237 // Read subfield IDs
7238 $this->SI1 = $this->compressed_data[$this->position++];
7239 $this->SI2 = $this->compressed_data[$this->position++];
7241 // SI2 set to zero is reserved for future use
7242 if ($this->SI2 === "\x00")
7247 // Get the length of the extra field
7248 $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
7249 $this->position += 2;
7251 // Check the length of the string is still valid
7252 $this->min_compressed_size += $len + 4;
7253 if ($this->compressed_size >= $this->min_compressed_size)
7255 // Set the extra field to the given data
7256 $this->extra_field = substr($this->compressed_data, $this->position, $len);
7257 $this->position += $len;
7266 if ($this->flags & 8)
7268 // Get the length of the filename
7269 $len = strcspn($this->compressed_data, "\x00", $this->position);
7271 // Check the length of the string is still valid
7272 $this->min_compressed_size += $len + 1;
7273 if ($this->compressed_size >= $this->min_compressed_size)
7275 // Set the original filename to the given string
7276 $this->filename = substr($this->compressed_data, $this->position, $len);
7277 $this->position += $len + 1;
7285 // Parse the FCOMMENT
7286 if ($this->flags & 16)
7288 // Get the length of the comment
7289 $len = strcspn($this->compressed_data, "\x00", $this->position);
7291 // Check the length of the string is still valid
7292 $this->min_compressed_size += $len + 1;
7293 if ($this->compressed_size >= $this->min_compressed_size)
7295 // Set the original comment to the given string
7296 $this->comment = substr($this->compressed_data, $this->position, $len);
7297 $this->position += $len + 1;
7306 if ($this->flags & 2)
7308 // Check the length of the string is still valid
7309 $this->min_compressed_size += $len + 2;
7310 if ($this->compressed_size >= $this->min_compressed_size)
7313 $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
7315 // Check the CRC matches
7316 if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
7318 $this->position += 2;
7331 // Decompress the actual data
7332 if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
7338 $this->position = $this->compressed_size - 8;
7341 // Check CRC of data
7342 $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
7343 $this->position += 4;
7344 /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
7349 // Check ISIZE of data
7350 $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
7351 $this->position += 4;
7352 if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
7357 // Wow, against all odds, we've actually got a valid gzip string
7368 * HTTP Response Parser
7370 * @package SimplePie
7373 class SimplePie_HTTP_Parser
7380 public $http_version = 0.0;
7387 public $status_code = 0;
7394 public $reason = '';
7397 * Key/value pairs of the headers
7401 public $headers = array();
7404 * Body of the response
7411 * Current state of the state machine
7415 protected $state = 'http_version';
7422 protected $data = '';
7425 * Input data length (to avoid calling strlen() everytime this is needed)
7429 protected $data_length = 0;
7432 * Current position of the pointer
7436 protected $position = 0;
7439 * Name of the hedaer currently being parsed
7443 protected $name = '';
7446 * Value of the hedaer currently being parsed
7450 protected $value = '';
7453 * Create an instance of the class with the input data
7455 * @param string $data Input data
7457 public function __construct($data)
7459 $this->data = $data;
7460 $this->data_length = strlen($this->data);
7464 * Parse the input data
7466 * @return bool true on success, false on failure
7468 public function parse()
7470 while ($this->state && $this->state !== 'emit' && $this->has_data())
7472 $state = $this->state;
7476 if ($this->state === 'emit' || $this->state === 'body')
7482 $this->http_version = '';
7483 $this->status_code = '';
7485 $this->headers = array();
7492 * Check whether there is data beyond the pointer
7494 * @return bool true if there is further data, false if not
7496 protected function has_data()
7498 return (bool) ($this->position < $this->data_length);
7502 * See if the next character is LWS
7504 * @return bool true if the next character is LWS, false if not
7506 protected function is_linear_whitespace()
7508 return (bool) ($this->data[$this->position] === "\x09"
7509 || $this->data[$this->position] === "\x20"
7510 || ($this->data[$this->position] === "\x0A"
7511 && isset($this->data[$this->position + 1])
7512 && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
7516 * Parse the HTTP version
7518 protected function http_version()
7520 if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
7522 $len = strspn($this->data, '0123456789.', 5);
7523 $this->http_version = substr($this->data, 5, $len);
7524 $this->position += 5 + $len;
7525 if (substr_count($this->http_version, '.') <= 1)
7527 $this->http_version = (float) $this->http_version;
7528 $this->position += strspn($this->data, "\x09\x20", $this->position);
7529 $this->state = 'status';
7533 $this->state = false;
7538 $this->state = false;
7543 * Parse the status code
7545 protected function status()
7547 if ($len = strspn($this->data, '0123456789', $this->position))
7549 $this->status_code = (int) substr($this->data, $this->position, $len);
7550 $this->position += $len;
7551 $this->state = 'reason';
7555 $this->state = false;
7560 * Parse the reason phrase
7562 protected function reason()
7564 $len = strcspn($this->data, "\x0A", $this->position);
7565 $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
7566 $this->position += $len + 1;
7567 $this->state = 'new_line';
7571 * Deal with a new line, shifting data around as needed
7573 protected function new_line()
7575 $this->value = trim($this->value, "\x0D\x20");
7576 if ($this->name !== '' && $this->value !== '')
7578 $this->name = strtolower($this->name);
7579 // We should only use the last Content-Type header. c.f. issue #1
7580 if (isset($this->headers[$this->name]) && $this->name !== 'content-type')
7582 $this->headers[$this->name] .= ', ' . $this->value;
7586 $this->headers[$this->name] = $this->value;
7591 if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
7593 $this->position += 2;
7594 $this->state = 'body';
7596 elseif ($this->data[$this->position] === "\x0A")
7599 $this->state = 'body';
7603 $this->state = 'name';
7608 * Parse a header name
7610 protected function name()
7612 $len = strcspn($this->data, "\x0A:", $this->position);
7613 if (isset($this->data[$this->position + $len]))
7615 if ($this->data[$this->position + $len] === "\x0A")
7617 $this->position += $len;
7618 $this->state = 'new_line';
7622 $this->name = substr($this->data, $this->position, $len);
7623 $this->position += $len + 1;
7624 $this->state = 'value';
7629 $this->state = false;
7634 * Parse LWS, replacing consecutive LWS characters with a single space
7636 protected function linear_whitespace()
7640 if (substr($this->data, $this->position, 2) === "\x0D\x0A")
7642 $this->position += 2;
7644 elseif ($this->data[$this->position] === "\x0A")
7648 $this->position += strspn($this->data, "\x09\x20", $this->position);
7649 } while ($this->has_data() && $this->is_linear_whitespace());
7650 $this->value .= "\x20";
7654 * See what state to move to while within non-quoted header values
7656 protected function value()
7658 if ($this->is_linear_whitespace())
7660 $this->linear_whitespace();
7664 switch ($this->data[$this->position])
7667 // Workaround for ETags: we have to include the quotes as
7669 if (strtolower($this->name) === 'etag')
7671 $this->value .= '"';
7673 $this->state = 'value_char';
7677 $this->state = 'quote';
7682 $this->state = 'new_line';
7686 $this->state = 'value_char';
7693 * Parse a header value while outside quotes
7695 protected function value_char()
7697 $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
7698 $this->value .= substr($this->data, $this->position, $len);
7699 $this->position += $len;
7700 $this->state = 'value';
7704 * See what state to move to while within quoted header values
7706 protected function quote()
7708 if ($this->is_linear_whitespace())
7710 $this->linear_whitespace();
7714 switch ($this->data[$this->position])
7718 $this->state = 'value';
7723 $this->state = 'new_line';
7728 $this->state = 'quote_escaped';
7732 $this->state = 'quote_char';
7739 * Parse a header value while within quotes
7741 protected function quote_char()
7743 $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
7744 $this->value .= substr($this->data, $this->position, $len);
7745 $this->position += $len;
7746 $this->state = 'value';
7750 * Parse an escaped character within quotes
7752 protected function quote_escaped()
7754 $this->value .= $this->data[$this->position];
7756 $this->state = 'quote';
7762 protected function body()
7764 $this->body = substr($this->data, $this->position);
7765 if (!empty($this->headers['transfer-encoding']))
7767 unset($this->headers['transfer-encoding']);
7768 $this->state = 'chunked';
7772 $this->state = 'emit';
7777 * Parsed a "Transfer-Encoding: chunked" body
7779 protected function chunked()
7781 if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body)))
7783 $this->state = 'emit';
7788 $encoded = $this->body;
7792 $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
7795 // Looks like it's not chunked after all
7796 $this->state = 'emit';
7800 $length = hexdec(trim($matches[1]));
7803 // Ignore trailer headers
7804 $this->state = 'emit';
7805 $this->body = $decoded;
7809 $chunk_length = strlen($matches[0]);
7810 $decoded .= $part = substr($encoded, $chunk_length, $length);
7811 $encoded = substr($encoded, $chunk_length + $length + 2);
7813 if (trim($encoded) === '0' || empty($encoded))
7815 $this->state = 'emit';
7816 $this->body = $decoded;
7824 * IRI parser/serialiser/normaliser
7826 * @package SimplePie
7828 * @author Geoffrey Sneddon
7829 * @author Steve Minutillo
7830 * @author Ryan McCue
7831 * @copyright 2007-2012 Geoffrey Sneddon, Steve Minutillo, Ryan McCue
7832 * @license http://www.opensource.org/licenses/bsd-license.php
7841 protected $scheme = null;
7848 protected $iuserinfo = null;
7855 protected $ihost = null;
7862 protected $port = null;
7869 protected $ipath = '';
7876 protected $iquery = null;
7883 protected $ifragment = null;
7886 * Normalization database
7888 * Each key is the scheme, each value is an array with each key as the IRI
7889 * part and value as the default value for that part.
7891 protected $normalization = array(
7899 'ihost' => 'localhost'
7912 * Return the entire IRI when you try and read the object as a string
7916 public function __toString()
7918 return $this->get_iri();
7922 * Overload __set() to provide access via properties
7924 * @param string $name Property name
7925 * @param mixed $value Property value
7927 public function __set($name, $value)
7929 if (method_exists($this, 'set_' . $name))
7931 call_user_func(array($this, 'set_' . $name), $value);
7934 $name === 'iauthority'
7935 || $name === 'iuserinfo'
7936 || $name === 'ihost'
7937 || $name === 'ipath'
7938 || $name === 'iquery'
7939 || $name === 'ifragment'
7942 call_user_func(array($this, 'set_' . substr($name, 1)), $value);
7947 * Overload __get() to provide access via properties
7949 * @param string $name Property name
7952 public function __get($name)
7954 // isset() returns false for null, we don't want to do that
7955 // Also why we use array_key_exists below instead of isset()
7956 $props = get_object_vars($this);
7961 $name === 'iauthority' ||
7962 $name === 'authority'
7965 $return = $this->{"get_$name"}();
7967 elseif (array_key_exists($name, $props))
7969 $return = $this->$name;
7972 elseif (($prop = 'i' . $name) && array_key_exists($prop, $props))
7975 $return = $this->$prop;
7977 // ischeme -> scheme
7978 elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props))
7981 $return = $this->$prop;
7985 trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
7989 if ($return === null && isset($this->normalization[$this->scheme][$name]))
7991 return $this->normalization[$this->scheme][$name];
8000 * Overload __isset() to provide access via properties
8002 * @param string $name Property name
8005 public function __isset($name)
8007 if (method_exists($this, 'get_' . $name) || isset($this->$name))
8018 * Overload __unset() to provide access via properties
8020 * @param string $name Property name
8022 public function __unset($name)
8024 if (method_exists($this, 'set_' . $name))
8026 call_user_func(array($this, 'set_' . $name), '');
8031 * Create a new IRI object, from a specified string
8033 * @param string $iri
8035 public function __construct($iri = null)
8037 $this->set_iri($iri);
8041 * Create a new IRI object by resolving a relative IRI
8043 * Returns false if $base is not absolute, otherwise an IRI.
8045 * @param IRI|string $base (Absolute) Base IRI
8046 * @param IRI|string $relative Relative IRI
8049 public static function absolutize($base, $relative)
8051 if (!($relative instanceof SimplePie_IRI))
8053 $relative = new SimplePie_IRI($relative);
8055 if (!$relative->is_valid())
8059 elseif ($relative->scheme !== null)
8061 return clone $relative;
8065 if (!($base instanceof SimplePie_IRI))
8067 $base = new SimplePie_IRI($base);
8069 if ($base->scheme !== null && $base->is_valid())
8071 if ($relative->get_iri() !== '')
8073 if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null)
8075 $target = clone $relative;
8076 $target->scheme = $base->scheme;
8080 $target = new SimplePie_IRI;
8081 $target->scheme = $base->scheme;
8082 $target->iuserinfo = $base->iuserinfo;
8083 $target->ihost = $base->ihost;
8084 $target->port = $base->port;
8085 if ($relative->ipath !== '')
8087 if ($relative->ipath[0] === '/')
8089 $target->ipath = $relative->ipath;
8091 elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '')
8093 $target->ipath = '/' . $relative->ipath;
8095 elseif (($last_segment = strrpos($base->ipath, '/')) !== false)
8097 $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
8101 $target->ipath = $relative->ipath;
8103 $target->ipath = $target->remove_dot_segments($target->ipath);
8104 $target->iquery = $relative->iquery;
8108 $target->ipath = $base->ipath;
8109 if ($relative->iquery !== null)
8111 $target->iquery = $relative->iquery;
8113 elseif ($base->iquery !== null)
8115 $target->iquery = $base->iquery;
8118 $target->ifragment = $relative->ifragment;
8123 $target = clone $base;
8124 $target->ifragment = null;
8126 $target->scheme_normalization();
8137 * Parse an IRI into scheme/authority/path/query/fragment segments
8139 * @param string $iri
8142 protected function parse_iri($iri)
8144 $iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
8145 if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match))
8147 if ($match[1] === '')
8149 $match['scheme'] = null;
8151 if (!isset($match[3]) || $match[3] === '')
8153 $match['authority'] = null;
8155 if (!isset($match[5]))
8157 $match['path'] = '';
8159 if (!isset($match[6]) || $match[6] === '')
8161 $match['query'] = null;
8163 if (!isset($match[8]) || $match[8] === '')
8165 $match['fragment'] = null;
8171 // This can occur when a paragraph is accidentally parsed as a URI
8177 * Remove dot segments from a path
8179 * @param string $input
8182 protected function remove_dot_segments($input)
8185 while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
8187 // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
8188 if (strpos($input, '../') === 0)
8190 $input = substr($input, 3);
8192 elseif (strpos($input, './') === 0)
8194 $input = substr($input, 2);
8196 // 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,
8197 elseif (strpos($input, '/./') === 0)
8199 $input = substr($input, 2);
8201 elseif ($input === '/.')
8205 // 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,
8206 elseif (strpos($input, '/../') === 0)
8208 $input = substr($input, 3);
8209 $output = substr_replace($output, '', strrpos($output, '/'));
8211 elseif ($input === '/..')
8214 $output = substr_replace($output, '', strrpos($output, '/'));
8216 // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
8217 elseif ($input === '.' || $input === '..')
8221 // 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
8222 elseif (($pos = strpos($input, '/', 1)) !== false)
8224 $output .= substr($input, 0, $pos);
8225 $input = substr_replace($input, '', 0, $pos);
8233 return $output . $input;
8237 * Replace invalid character with percent encoding
8239 * @param string $string Input string
8240 * @param string $extra_chars Valid characters not in iunreserved or
8241 * iprivate (this is ASCII-only)
8242 * @param bool $iprivate Allow iprivate
8245 protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false)
8247 // Normalize as many pct-encoded sections as possible
8248 $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string);
8250 // Replace invalid percent characters
8251 $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
8253 // Add unreserved and % to $extra_chars (the latter is safe because all
8254 // pct-encoded sections are now valid).
8255 $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
8257 // Now replace any bytes that aren't allowed with their pct-encoded versions
8259 $strlen = strlen($string);
8260 while (($position += strspn($string, $extra_chars, $position)) < $strlen)
8262 $value = ord($string[$position]);
8267 // By default we are valid
8270 // No one byte sequences are valid due to the while.
8271 // Two byte sequence:
8272 if (($value & 0xE0) === 0xC0)
8274 $character = ($value & 0x1F) << 6;
8278 // Three byte sequence:
8279 elseif (($value & 0xF0) === 0xE0)
8281 $character = ($value & 0x0F) << 12;
8285 // Four byte sequence:
8286 elseif (($value & 0xF8) === 0xF0)
8288 $character = ($value & 0x07) << 18;
8302 if ($position + $length <= $strlen)
8304 for ($position++; $remaining; $position++)
8306 $value = ord($string[$position]);
8308 // Check that the byte is valid, then add it to the character:
8309 if (($value & 0xC0) === 0x80)
8311 $character |= ($value & 0x3F) << (--$remaining * 6);
8313 // If it is invalid, count the sequence as invalid and reprocess the current byte:
8324 $position = $strlen - 1;
8329 // Percent encode anything invalid or not in ucschar
8331 // Invalid sequences
8333 // Non-shortest form sequences are invalid
8334 || $length > 1 && $character <= 0x7F
8335 || $length > 2 && $character <= 0x7FF
8336 || $length > 3 && $character <= 0xFFFF
8337 // Outside of range of ucschar codepoints
8339 || ($character & 0xFFFE) === 0xFFFE
8340 || $character >= 0xFDD0 && $character <= 0xFDEF
8342 // Everything else not in ucschar
8343 $character > 0xD7FF && $character < 0xF900
8344 || $character < 0xA0
8345 || $character > 0xEFFFD
8348 // Everything not in iprivate, if it applies
8350 || $character < 0xE000
8351 || $character > 0x10FFFD
8355 // If we were a character, pretend we weren't, but rather an error.
8359 for ($j = $start; $j <= $position; $j++)
8361 $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
8373 * Callback function for preg_replace_callback.
8375 * Removes sequences of percent encoded bytes that represent UTF-8
8376 * encoded characters in iunreserved
8378 * @param array $match PCRE match
8379 * @return string Replacement
8381 protected function remove_iunreserved_percent_encoded($match)
8383 // As we just have valid percent encoded sequences we can just explode
8384 // and ignore the first member of the returned array (an empty string).
8385 $bytes = explode('%', $match[0]);
8387 // Initialize the new string (this is what will be returned) and that
8388 // there are no bytes remaining in the current sequence (unsurprising
8389 // at the first byte!).
8393 // Loop over each and every byte, and set $value to its value
8394 for ($i = 1, $len = count($bytes); $i < $len; $i++)
8396 $value = hexdec($bytes[$i]);
8398 // If we're the first byte of sequence:
8404 // By default we are valid
8407 // One byte sequence:
8410 $character = $value;
8413 // Two byte sequence:
8414 elseif (($value & 0xE0) === 0xC0)
8416 $character = ($value & 0x1F) << 6;
8420 // Three byte sequence:
8421 elseif (($value & 0xF0) === 0xE0)
8423 $character = ($value & 0x0F) << 12;
8427 // Four byte sequence:
8428 elseif (($value & 0xF8) === 0xF0)
8430 $character = ($value & 0x07) << 18;
8441 // Continuation byte:
8444 // Check that the byte is valid, then add it to the character:
8445 if (($value & 0xC0) === 0x80)
8448 $character |= ($value & 0x3F) << ($remaining * 6);
8450 // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
8459 // If we've reached the end of the current byte sequence, append it to Unicode::$data
8462 // Percent encode anything invalid or not in iunreserved
8464 // Invalid sequences
8466 // Non-shortest form sequences are invalid
8467 || $length > 1 && $character <= 0x7F
8468 || $length > 2 && $character <= 0x7FF
8469 || $length > 3 && $character <= 0xFFFF
8470 // Outside of range of iunreserved codepoints
8471 || $character < 0x2D
8472 || $character > 0xEFFFD
8474 || ($character & 0xFFFE) === 0xFFFE
8475 || $character >= 0xFDD0 && $character <= 0xFDEF
8476 // Everything else not in iunreserved (this is all BMP)
8477 || $character === 0x2F
8478 || $character > 0x39 && $character < 0x41
8479 || $character > 0x5A && $character < 0x61
8480 || $character > 0x7A && $character < 0x7E
8481 || $character > 0x7E && $character < 0xA0
8482 || $character > 0xD7FF && $character < 0xF900
8485 for ($j = $start; $j <= $i; $j++)
8487 $string .= '%' . strtoupper($bytes[$j]);
8492 for ($j = $start; $j <= $i; $j++)
8494 $string .= chr(hexdec($bytes[$j]));
8500 // If we have any bytes left over they are invalid (i.e., we are
8501 // mid-way through a multi-byte sequence)
8504 for ($j = $start; $j < $len; $j++)
8506 $string .= '%' . strtoupper($bytes[$j]);
8513 protected function scheme_normalization()
8515 if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo'])
8517 $this->iuserinfo = null;
8519 if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost'])
8521 $this->ihost = null;
8523 if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port'])
8527 if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath'])
8531 if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery'])
8533 $this->iquery = null;
8535 if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment'])
8537 $this->ifragment = null;
8542 * Check if the object represents a valid IRI. This needs to be done on each
8543 * call as some things change depending on another part of the IRI.
8547 public function is_valid()
8549 $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
8550 if ($this->ipath !== '' &&
8553 $this->ipath[0] !== '/' ||
8554 substr($this->ipath, 0, 2) === '//'
8557 $this->scheme === null &&
8559 strpos($this->ipath, ':') !== false &&
8560 (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
8572 * Set the entire IRI. Returns true on success, false on failure (if there
8573 * are any invalid characters).
8575 * @param string $iri
8578 public function set_iri($iri)
8590 elseif (isset($cache[$iri]))
8599 $return) = $cache[$iri];
8604 $parsed = $this->parse_iri((string) $iri);
8610 $return = $this->set_scheme($parsed['scheme'])
8611 && $this->set_authority($parsed['authority'])
8612 && $this->set_path($parsed['path'])
8613 && $this->set_query($parsed['query'])
8614 && $this->set_fragment($parsed['fragment']);
8616 $cache[$iri] = array($this->scheme,
8629 * Set the scheme. Returns true on success, false on failure (if there are
8630 * any invalid characters).
8632 * @param string $scheme
8635 public function set_scheme($scheme)
8637 if ($scheme === null)
8639 $this->scheme = null;
8641 elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme))
8643 $this->scheme = null;
8648 $this->scheme = strtolower($scheme);
8654 * Set the authority. Returns true on success, false on failure (if there are
8655 * any invalid characters).
8657 * @param string $authority
8660 public function set_authority($authority)
8666 if ($authority === null)
8668 $this->iuserinfo = null;
8669 $this->ihost = null;
8673 elseif (isset($cache[$authority]))
8675 list($this->iuserinfo,
8678 $return) = $cache[$authority];
8684 $remaining = $authority;
8685 if (($iuserinfo_end = strrpos($remaining, '@')) !== false)
8687 $iuserinfo = substr($remaining, 0, $iuserinfo_end);
8688 $remaining = substr($remaining, $iuserinfo_end + 1);
8694 if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false)
8696 if (($port = substr($remaining, $port_start + 1)) === false)
8700 $remaining = substr($remaining, 0, $port_start);
8707 $return = $this->set_userinfo($iuserinfo) &&
8708 $this->set_host($remaining) &&
8709 $this->set_port($port);
8711 $cache[$authority] = array($this->iuserinfo,
8721 * Set the iuserinfo.
8723 * @param string $iuserinfo
8726 public function set_userinfo($iuserinfo)
8728 if ($iuserinfo === null)
8730 $this->iuserinfo = null;
8734 $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
8735 $this->scheme_normalization();
8742 * Set the ihost. Returns true on success, false on failure (if there are
8743 * any invalid characters).
8745 * @param string $ihost
8748 public function set_host($ihost)
8750 if ($ihost === null)
8752 $this->ihost = null;
8755 elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']')
8757 if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1)))
8759 $this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']';
8763 $this->ihost = null;
8769 $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
8771 // Lowercase, but ignore pct-encoded sections (as they should
8772 // remain uppercase). This must be done after the previous step
8773 // as that can add unescaped characters.
8775 $strlen = strlen($ihost);
8776 while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen)
8778 if ($ihost[$position] === '%')
8784 $ihost[$position] = strtolower($ihost[$position]);
8789 $this->ihost = $ihost;
8792 $this->scheme_normalization();
8798 * Set the port. Returns true on success, false on failure (if there are
8799 * any invalid characters).
8801 * @param string $port
8804 public function set_port($port)
8811 elseif (strspn($port, '0123456789') === strlen($port))
8813 $this->port = (int) $port;
8814 $this->scheme_normalization();
8827 * @param string $ipath
8830 public function set_path($ipath)
8838 $ipath = (string) $ipath;
8840 if (isset($cache[$ipath]))
8842 $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
8846 $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
8847 $removed = $this->remove_dot_segments($valid);
8849 $cache[$ipath] = array($valid, $removed);
8850 $this->ipath = ($this->scheme !== null) ? $removed : $valid;
8853 $this->scheme_normalization();
8860 * @param string $iquery
8863 public function set_query($iquery)
8865 if ($iquery === null)
8867 $this->iquery = null;
8871 $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
8872 $this->scheme_normalization();
8878 * Set the ifragment.
8880 * @param string $ifragment
8883 public function set_fragment($ifragment)
8885 if ($ifragment === null)
8887 $this->ifragment = null;
8891 $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
8892 $this->scheme_normalization();
8898 * Convert an IRI to a URI (or parts thereof)
8902 public function to_uri($string)
8907 $non_ascii = implode('', range("\x80", "\xFF"));
8911 $strlen = strlen($string);
8912 while (($position += strcspn($string, $non_ascii, $position)) < $strlen)
8914 $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
8923 * Get the complete IRI
8927 public function get_iri()
8929 if (!$this->is_valid())
8935 if ($this->scheme !== null)
8937 $iri .= $this->scheme . ':';
8939 if (($iauthority = $this->get_iauthority()) !== null)
8941 $iri .= '//' . $iauthority;
8943 if ($this->ipath !== '')
8945 $iri .= $this->ipath;
8947 elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '')
8949 $iri .= $this->normalization[$this->scheme]['ipath'];
8951 if ($this->iquery !== null)
8953 $iri .= '?' . $this->iquery;
8955 if ($this->ifragment !== null)
8957 $iri .= '#' . $this->ifragment;
8964 * Get the complete URI
8968 public function get_uri()
8970 return $this->to_uri($this->get_iri());
8974 * Get the complete iauthority
8978 protected function get_iauthority()
8980 if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null)
8983 if ($this->iuserinfo !== null)
8985 $iauthority .= $this->iuserinfo . '@';
8987 if ($this->ihost !== null)
8989 $iauthority .= $this->ihost;
8991 if ($this->port !== null)
8993 $iauthority .= ':' . $this->port;
9004 * Get the complete authority
9008 protected function get_authority()
9010 $iauthority = $this->get_iauthority();
9011 if (is_string($iauthority))
9012 return $this->to_uri($iauthority);
9019 * Manages all item-related data
9021 * Used by {@see SimplePie::get_item()} and {@see SimplePie::get_items()}
9023 * This class can be overloaded with {@see SimplePie::set_item_class()}
9025 * @package SimplePie
9028 class SimplePie_Item
9044 var $data = array();
9050 * @var SimplePie_Registry
9052 protected $registry;
9055 * Create a new item object
9057 * This is usually used by {@see SimplePie::get_items} and
9058 * {@see SimplePie::get_item}. Avoid creating this manually.
9060 * @param SimplePie $feed Parent feed
9061 * @param array $data Raw data
9063 public function __construct($feed, $data)
9065 $this->feed = $feed;
9066 $this->data = $data;
9070 * Set the registry handler
9072 * This is usually used by {@see SimplePie_Registry::create}
9075 * @param SimplePie_Registry $registry
9077 public function set_registry(SimplePie_Registry $registry)
9079 $this->registry = $registry;
9083 * Get a string representation of the item
9087 public function __toString()
9089 return md5(serialize($this->data));
9093 * Remove items that link back to this before destroying this object
9095 public function __destruct()
9097 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
9104 * Get data for an item-level element
9106 * This method allows you to get access to ANY element/attribute that is a
9107 * sub-element of the item/entry tag.
9109 * See {@see SimplePie::get_feed_tags()} for a description of the return value
9112 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
9113 * @param string $namespace The URL of the XML namespace of the elements you're trying to access
9114 * @param string $tag Tag name
9117 public function get_item_tags($namespace, $tag)
9119 if (isset($this->data['child'][$namespace][$tag]))
9121 return $this->data['child'][$namespace][$tag];
9130 * Get the base URL value from the parent feed
9134 * @param array $element
9137 public function get_base($element = array())
9139 return $this->feed->get_base($element);
9143 * Sanitize feed data
9146 * @see SimplePie::sanitize()
9147 * @param string $data Data to sanitize
9148 * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
9149 * @param string $base Base URL to resolve URLs against
9150 * @return string Sanitized data
9152 public function sanitize($data, $type, $base = '')
9154 return $this->feed->sanitize($data, $type, $base);
9158 * Get the parent feed
9160 * Note: this may not work as you think for multifeeds!
9162 * @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed
9166 public function get_feed()
9172 * Get the unique identifier for the item
9174 * This is usually used when writing code to check for new items in a feed.
9176 * Uses `<atom:id>`, `<guid>`, `<dc:identifier>` or the `about` attribute
9177 * for RDF. If none of these are supplied (or `$hash` is true), creates an
9178 * MD5 hash based on the permalink and title. If either of those are not
9179 * supplied, creates a hash based on the full feed data.
9182 * @param boolean $hash Should we force using a hash instead of the supplied ID?
9185 public function get_id($hash = false)
9189 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
9191 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9193 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
9195 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9197 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
9199 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9201 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
9203 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9205 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
9207 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9209 elseif (isset($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about']))
9211 return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT);
9213 elseif (($return = $this->get_permalink()) !== null)
9217 elseif (($return = $this->get_title()) !== null)
9222 if ($this->get_permalink() !== null || $this->get_title() !== null)
9224 return md5($this->get_permalink() . $this->get_title());
9228 return md5(serialize($this->data));
9233 * Get the title of the item
9235 * Uses `<atom:title>`, `<title>` or `<dc:title>`
9237 * @since Beta 2 (previously called `get_item_title` since 0.8)
9238 * @return string|null
9240 public function get_title()
9242 if (!isset($this->data['title']))
9244 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
9246 $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]));
9248 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
9250 $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]));
9252 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
9254 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9256 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
9258 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9260 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
9262 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9264 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
9266 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9268 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
9270 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9274 $this->data['title'] = null;
9277 return $this->data['title'];
9281 * Get the content for the item
9283 * Prefers summaries over full content , but will return full content if a
9284 * summary does not exist.
9286 * To prefer full content instead, use {@see get_content}
9288 * Uses `<atom:summary>`, `<description>`, `<dc:description>` or
9289 * `<itunes:subtitle>`
9292 * @param boolean $description_only Should we avoid falling back to the content?
9293 * @return string|null
9295 public function get_description($description_only = false)
9297 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
9299 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9301 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
9303 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9305 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
9307 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9309 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
9311 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
9313 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
9315 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9317 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
9319 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9321 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
9323 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
9325 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
9327 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9329 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
9331 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
9334 elseif (!$description_only)
9336 return $this->get_content(true);
9345 * Get the content for the item
9347 * Prefers full content over summaries, but will return a summary if full
9348 * content does not exist.
9350 * To prefer summaries instead, use {@see get_description}
9352 * Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module)
9355 * @param boolean $content_only Should we avoid falling back to the description?
9356 * @return string|null
9358 public function get_content($content_only = false)
9360 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
9362 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_content_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9364 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
9366 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9368 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
9370 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
9372 elseif (!$content_only)
9374 return $this->get_description(true);
9383 * Get a category for the item
9385 * @since Beta 3 (previously called `get_categories()` since Beta 2)
9386 * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
9387 * @return SimplePie_Category|null
9389 public function get_category($key = 0)
9391 $categories = $this->get_categories();
9392 if (isset($categories[$key]))
9394 return $categories[$key];
9403 * Get all categories for the item
9405 * Uses `<atom:category>`, `<category>` or `<dc:subject>`
9408 * @return array|null List of {@see SimplePie_Category} objects
9410 public function get_categories()
9412 $categories = array();
9414 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
9419 if (isset($category['attribs']['']['term']))
9421 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
9423 if (isset($category['attribs']['']['scheme']))
9425 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
9427 if (isset($category['attribs']['']['label']))
9429 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
9431 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
9433 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
9435 // This is really the label, but keep this as the term also for BC.
9436 // Label will also work on retrieving because that falls back to term.
9437 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9438 if (isset($category['attribs']['']['domain']))
9440 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
9446 $categories[] = $this->registry->create('Category', array($term, $scheme, null));
9448 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
9450 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9452 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
9454 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9457 if (!empty($categories))
9459 return array_unique($categories);
9468 * Get an author for the item
9471 * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
9472 * @return SimplePie_Author|null
9474 public function get_author($key = 0)
9476 $authors = $this->get_authors();
9477 if (isset($authors[$key]))
9479 return $authors[$key];
9488 * Get a contributor for the item
9491 * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
9492 * @return SimplePie_Author|null
9494 public function get_contributor($key = 0)
9496 $contributors = $this->get_contributors();
9497 if (isset($contributors[$key]))
9499 return $contributors[$key];
9508 * Get all contributors for the item
9510 * Uses `<atom:contributor>`
9513 * @return array|null List of {@see SimplePie_Author} objects
9515 public function get_contributors()
9517 $contributors = array();
9518 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
9523 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
9525 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9527 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
9529 $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]));
9531 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
9533 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9535 if ($name !== null || $email !== null || $uri !== null)
9537 $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
9540 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
9545 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
9547 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9549 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
9551 $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]));
9553 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
9555 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9557 if ($name !== null || $email !== null || $url !== null)
9559 $contributors[] = $this->registry->create('Author', array($name, $url, $email));
9563 if (!empty($contributors))
9565 return array_unique($contributors);
9574 * Get all authors for the item
9576 * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
9579 * @return array|null List of {@see SimplePie_Author} objects
9581 public function get_authors()
9584 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
9589 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
9591 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9593 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
9595 $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]));
9597 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
9599 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9601 if ($name !== null || $email !== null || $uri !== null)
9603 $authors[] = $this->registry->create('Author', array($name, $uri, $email));
9606 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
9611 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
9613 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9615 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
9617 $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]));
9619 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
9621 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9623 if ($name !== null || $email !== null || $url !== null)
9625 $authors[] = $this->registry->create('Author', array($name, $url, $email));
9628 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
9630 $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)));
9632 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
9634 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9636 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
9638 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9640 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
9642 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9645 if (!empty($authors))
9647 return array_unique($authors);
9649 elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
9653 elseif ($authors = $this->feed->get_authors())
9664 * Get the copyright info for the item
9666 * Uses `<atom:rights>` or `<dc:rights>`
9671 public function get_copyright()
9673 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
9675 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9677 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
9679 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9681 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
9683 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9692 * Get the posting date/time for the item
9694 * Uses `<atom:published>`, `<atom:updated>`, `<atom:issued>`,
9695 * `<atom:modified>`, `<pubDate>` or `<dc:date>`
9697 * Note: obeys PHP's timezone setting. To get a UTC date/time, use
9700 * @since Beta 2 (previously called `get_item_date` since 0.8)
9702 * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
9703 * @return int|string|null
9705 public function get_date($date_format = 'j F Y, g:i a')
9707 if (!isset($this->data['date']))
9709 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
9711 $this->data['date']['raw'] = $return[0]['data'];
9713 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
9715 $this->data['date']['raw'] = $return[0]['data'];
9717 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
9719 $this->data['date']['raw'] = $return[0]['data'];
9721 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
9723 $this->data['date']['raw'] = $return[0]['data'];
9725 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
9727 $this->data['date']['raw'] = $return[0]['data'];
9729 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
9731 $this->data['date']['raw'] = $return[0]['data'];
9733 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
9735 $this->data['date']['raw'] = $return[0]['data'];
9737 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
9739 $this->data['date']['raw'] = $return[0]['data'];
9742 if (!empty($this->data['date']['raw']))
9744 $parser = $this->registry->call('Parse_Date', 'get');
9745 $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
9749 $this->data['date'] = null;
9752 if ($this->data['date'])
9754 $date_format = (string) $date_format;
9755 switch ($date_format)
9758 return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
9761 return $this->data['date']['parsed'];
9764 return date($date_format, $this->data['date']['parsed']);
9774 * Get the update date/time for the item
9776 * Uses `<atom:updated>`
9778 * Note: obeys PHP's timezone setting. To get a UTC date/time, use
9781 * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
9782 * @return int|string|null
9784 public function get_updated_date($date_format = 'j F Y, g:i a')
9786 if (!isset($this->data['updated']))
9788 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
9790 $this->data['updated']['raw'] = $return[0]['data'];
9793 if (!empty($this->data['updated']['raw']))
9795 $parser = $this->registry->call('Parse_Date', 'get');
9796 $this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']);
9800 $this->data['updated'] = null;
9803 if ($this->data['updated'])
9805 $date_format = (string) $date_format;
9806 switch ($date_format)
9809 return $this->sanitize($this->data['updated']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
9812 return $this->data['updated']['parsed'];
9815 return date($date_format, $this->data['updated']['parsed']);
9825 * Get the localized posting date/time for the item
9827 * Returns the date formatted in the localized language. To display in
9828 * languages other than the server's default, you need to change the locale
9829 * with {@link http://php.net/setlocale setlocale()}. The available
9830 * localizations depend on which ones are installed on your web server.
9834 * @param string $date_format Supports any PHP date format from {@see http://php.net/strftime} (empty for the raw data)
9835 * @return int|string|null
9837 public function get_local_date($date_format = '%c')
9841 return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
9843 elseif (($date = $this->get_date('U')) !== null && $date !== false)
9845 return strftime($date_format, $date);
9854 * Get the posting date/time for the item (UTC time)
9857 * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
9858 * @return int|string|null
9860 public function get_gmdate($date_format = 'j F Y, g:i a')
9862 $date = $this->get_date('U');
9868 return gmdate($date_format, $date);
9872 * Get the update date/time for the item (UTC time)
9874 * @see get_updated_date
9875 * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
9876 * @return int|string|null
9878 public function get_updated_gmdate($date_format = 'j F Y, g:i a')
9880 $date = $this->get_updated_date('U');
9886 return gmdate($date_format, $date);
9890 * Get the permalink for the item
9892 * Returns the first link available with a relationship of "alternate".
9893 * Identical to {@see get_link()} with key 0
9897 * @return string|null Permalink URL
9899 public function get_permalink()
9901 $link = $this->get_link();
9902 $enclosure = $this->get_enclosure(0);
9907 elseif ($enclosure !== null)
9909 return $enclosure->get_link();
9918 * Get a single link for the item
9921 * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
9922 * @param string $rel The relationship of the link to return
9923 * @return string|null Link URL
9925 public function get_link($key = 0, $rel = 'alternate')
9927 $links = $this->get_links($rel);
9928 if ($links[$key] !== null)
9930 return $links[$key];
9939 * Get all links for the item
9941 * Uses `<atom:link>`, `<link>` or `<guid>`
9944 * @param string $rel The relationship of links to return
9945 * @return array|null Links found for the item (strings)
9947 public function get_links($rel = 'alternate')
9949 if (!isset($this->data['links']))
9951 $this->data['links'] = array();
9952 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
9954 if (isset($link['attribs']['']['href']))
9956 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
9957 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
9961 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
9963 if (isset($link['attribs']['']['href']))
9965 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
9966 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
9969 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
9971 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9973 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
9975 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9977 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
9979 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9981 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
9983 if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true')
9985 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9989 $keys = array_keys($this->data['links']);
9990 foreach ($keys as $key)
9992 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
9994 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
9996 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
9997 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
10001 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
10004 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
10006 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
10008 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
10011 if (isset($this->data['links'][$rel]))
10013 return $this->data['links'][$rel];
10022 * Get an enclosure from the item
10024 * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
10027 * @todo Add ability to prefer one type of content over another (in a media group).
10028 * @param int $key The enclosure that you want to return. Remember that arrays begin with 0, not 1
10029 * @return SimplePie_Enclosure|null
10031 public function get_enclosure($key = 0, $prefer = null)
10033 $enclosures = $this->get_enclosures();
10034 if (isset($enclosures[$key]))
10036 return $enclosures[$key];
10045 * Get all available enclosures (podcasts, etc.)
10047 * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
10049 * At this point, we're pretty much assuming that all enclosures for an item
10050 * are the same content. Anything else is too complicated to
10051 * properly support.
10054 * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
10055 * @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).
10056 * @return array|null List of SimplePie_Enclosure items
10058 public function get_enclosures()
10060 if (!isset($this->data['enclosures']))
10062 $this->data['enclosures'] = array();
10065 $captions_parent = null;
10066 $categories_parent = null;
10067 $copyrights_parent = null;
10068 $credits_parent = null;
10069 $description_parent = null;
10070 $duration_parent = null;
10071 $hashes_parent = null;
10072 $keywords_parent = null;
10073 $player_parent = null;
10074 $ratings_parent = null;
10075 $restrictions_parent = null;
10076 $thumbnails_parent = null;
10077 $title_parent = null;
10079 // Let's do the channel and item-level ones first, and just re-use them if we need to.
10080 $parent = $this->get_feed();
10083 if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
10085 foreach ($captions as $caption)
10087 $caption_type = null;
10088 $caption_lang = null;
10089 $caption_startTime = null;
10090 $caption_endTime = null;
10091 $caption_text = null;
10092 if (isset($caption['attribs']['']['type']))
10094 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10096 if (isset($caption['attribs']['']['lang']))
10098 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10100 if (isset($caption['attribs']['']['start']))
10102 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10104 if (isset($caption['attribs']['']['end']))
10106 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10108 if (isset($caption['data']))
10110 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10112 $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10115 elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
10117 foreach ($captions as $caption)
10119 $caption_type = null;
10120 $caption_lang = null;
10121 $caption_startTime = null;
10122 $caption_endTime = null;
10123 $caption_text = null;
10124 if (isset($caption['attribs']['']['type']))
10126 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10128 if (isset($caption['attribs']['']['lang']))
10130 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10132 if (isset($caption['attribs']['']['start']))
10134 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10136 if (isset($caption['attribs']['']['end']))
10138 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10140 if (isset($caption['data']))
10142 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10144 $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10147 if (is_array($captions_parent))
10149 $captions_parent = array_values(array_unique($captions_parent));
10153 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
10158 if (isset($category['data']))
10160 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10162 if (isset($category['attribs']['']['scheme']))
10164 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10168 $scheme = 'http://search.yahoo.com/mrss/category_schema';
10170 if (isset($category['attribs']['']['label']))
10172 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10174 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10176 foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
10181 if (isset($category['data']))
10183 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10185 if (isset($category['attribs']['']['scheme']))
10187 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10191 $scheme = 'http://search.yahoo.com/mrss/category_schema';
10193 if (isset($category['attribs']['']['label']))
10195 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10197 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10199 foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
10202 $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
10204 if (isset($category['attribs']['']['text']))
10206 $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
10208 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10210 if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
10212 foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory)
10214 if (isset($subcategory['attribs']['']['text']))
10216 $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
10218 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10222 if (is_array($categories_parent))
10224 $categories_parent = array_values(array_unique($categories_parent));
10228 if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
10230 $copyright_url = null;
10231 $copyright_label = null;
10232 if (isset($copyright[0]['attribs']['']['url']))
10234 $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10236 if (isset($copyright[0]['data']))
10238 $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10240 $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10242 elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
10244 $copyright_url = null;
10245 $copyright_label = null;
10246 if (isset($copyright[0]['attribs']['']['url']))
10248 $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10250 if (isset($copyright[0]['data']))
10252 $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10254 $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10258 if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
10260 foreach ($credits as $credit)
10262 $credit_role = null;
10263 $credit_scheme = null;
10264 $credit_name = null;
10265 if (isset($credit['attribs']['']['role']))
10267 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
10269 if (isset($credit['attribs']['']['scheme']))
10271 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10275 $credit_scheme = 'urn:ebu';
10277 if (isset($credit['data']))
10279 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10281 $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
10284 elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
10286 foreach ($credits as $credit)
10288 $credit_role = null;
10289 $credit_scheme = null;
10290 $credit_name = null;
10291 if (isset($credit['attribs']['']['role']))
10293 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
10295 if (isset($credit['attribs']['']['scheme']))
10297 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10301 $credit_scheme = 'urn:ebu';
10303 if (isset($credit['data']))
10305 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10307 $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
10310 if (is_array($credits_parent))
10312 $credits_parent = array_values(array_unique($credits_parent));
10316 if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
10318 if (isset($description_parent[0]['data']))
10320 $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10323 elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
10325 if (isset($description_parent[0]['data']))
10327 $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10332 if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration'))
10337 if (isset($duration_parent[0]['data']))
10339 $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10340 if (sizeof($temp) > 0)
10342 $seconds = (int) array_pop($temp);
10344 if (sizeof($temp) > 0)
10346 $minutes = (int) array_pop($temp);
10347 $seconds += $minutes * 60;
10349 if (sizeof($temp) > 0)
10351 $hours = (int) array_pop($temp);
10352 $seconds += $hours * 3600;
10355 $duration_parent = $seconds;
10360 if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
10362 foreach ($hashes_iterator as $hash)
10366 if (isset($hash['data']))
10368 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10370 if (isset($hash['attribs']['']['algo']))
10372 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
10378 $hashes_parent[] = $algo.':'.$value;
10381 elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
10383 foreach ($hashes_iterator as $hash)
10387 if (isset($hash['data']))
10389 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10391 if (isset($hash['attribs']['']['algo']))
10393 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
10399 $hashes_parent[] = $algo.':'.$value;
10402 if (is_array($hashes_parent))
10404 $hashes_parent = array_values(array_unique($hashes_parent));
10408 if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
10410 if (isset($keywords[0]['data']))
10412 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10413 foreach ($temp as $word)
10415 $keywords_parent[] = trim($word);
10420 elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
10422 if (isset($keywords[0]['data']))
10424 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10425 foreach ($temp as $word)
10427 $keywords_parent[] = trim($word);
10432 elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
10434 if (isset($keywords[0]['data']))
10436 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10437 foreach ($temp as $word)
10439 $keywords_parent[] = trim($word);
10444 elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
10446 if (isset($keywords[0]['data']))
10448 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10449 foreach ($temp as $word)
10451 $keywords_parent[] = trim($word);
10456 if (is_array($keywords_parent))
10458 $keywords_parent = array_values(array_unique($keywords_parent));
10462 if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
10464 if (isset($player_parent[0]['attribs']['']['url']))
10466 $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10469 elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
10471 if (isset($player_parent[0]['attribs']['']['url']))
10473 $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10478 if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
10480 foreach ($ratings as $rating)
10482 $rating_scheme = null;
10483 $rating_value = null;
10484 if (isset($rating['attribs']['']['scheme']))
10486 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10490 $rating_scheme = 'urn:simple';
10492 if (isset($rating['data']))
10494 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10496 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
10499 elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
10501 foreach ($ratings as $rating)
10503 $rating_scheme = 'urn:itunes';
10504 $rating_value = null;
10505 if (isset($rating['data']))
10507 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10509 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
10512 elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
10514 foreach ($ratings as $rating)
10516 $rating_scheme = null;
10517 $rating_value = null;
10518 if (isset($rating['attribs']['']['scheme']))
10520 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10524 $rating_scheme = 'urn:simple';
10526 if (isset($rating['data']))
10528 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10530 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
10533 elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
10535 foreach ($ratings as $rating)
10537 $rating_scheme = 'urn:itunes';
10538 $rating_value = null;
10539 if (isset($rating['data']))
10541 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10543 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
10546 if (is_array($ratings_parent))
10548 $ratings_parent = array_values(array_unique($ratings_parent));
10552 if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
10554 foreach ($restrictions as $restriction)
10556 $restriction_relationship = null;
10557 $restriction_type = null;
10558 $restriction_value = null;
10559 if (isset($restriction['attribs']['']['relationship']))
10561 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
10563 if (isset($restriction['attribs']['']['type']))
10565 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10567 if (isset($restriction['data']))
10569 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10571 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
10574 elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
10576 foreach ($restrictions as $restriction)
10578 $restriction_relationship = 'allow';
10579 $restriction_type = null;
10580 $restriction_value = 'itunes';
10581 if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
10583 $restriction_relationship = 'deny';
10585 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
10588 elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
10590 foreach ($restrictions as $restriction)
10592 $restriction_relationship = null;
10593 $restriction_type = null;
10594 $restriction_value = null;
10595 if (isset($restriction['attribs']['']['relationship']))
10597 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
10599 if (isset($restriction['attribs']['']['type']))
10601 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10603 if (isset($restriction['data']))
10605 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10607 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
10610 elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
10612 foreach ($restrictions as $restriction)
10614 $restriction_relationship = 'allow';
10615 $restriction_type = null;
10616 $restriction_value = 'itunes';
10617 if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
10619 $restriction_relationship = 'deny';
10621 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
10624 if (is_array($restrictions_parent))
10626 $restrictions_parent = array_values(array_unique($restrictions_parent));
10630 $restrictions_parent = array(new SimplePie_Restriction('allow', null, 'default'));
10634 if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
10636 foreach ($thumbnails as $thumbnail)
10638 if (isset($thumbnail['attribs']['']['url']))
10640 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10644 elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
10646 foreach ($thumbnails as $thumbnail)
10648 if (isset($thumbnail['attribs']['']['url']))
10650 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10656 if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
10658 if (isset($title_parent[0]['data']))
10660 $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10663 elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
10665 if (isset($title_parent[0]['data']))
10667 $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10671 // Clear the memory
10678 $expression = null;
10681 $javascript = null;
10685 $samplingrate = null;
10692 $categories = null;
10693 $copyrights = null;
10695 $description = null;
10700 $restrictions = null;
10701 $thumbnails = null;
10704 // If we have media:group tags, loop through them.
10705 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group)
10707 if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
10709 // If we have media:content tags, loop through them.
10710 foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
10712 if (isset($content['attribs']['']['url']))
10718 $expression = null;
10721 $javascript = null;
10725 $samplingrate = null;
10732 $categories = null;
10733 $copyrights = null;
10735 $description = null;
10740 $restrictions = null;
10741 $thumbnails = null;
10744 // Start checking the attributes of media:content
10745 if (isset($content['attribs']['']['bitrate']))
10747 $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
10749 if (isset($content['attribs']['']['channels']))
10751 $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
10753 if (isset($content['attribs']['']['duration']))
10755 $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
10759 $duration = $duration_parent;
10761 if (isset($content['attribs']['']['expression']))
10763 $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
10765 if (isset($content['attribs']['']['framerate']))
10767 $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
10769 if (isset($content['attribs']['']['height']))
10771 $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
10773 if (isset($content['attribs']['']['lang']))
10775 $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10777 if (isset($content['attribs']['']['fileSize']))
10779 $length = ceil($content['attribs']['']['fileSize']);
10781 if (isset($content['attribs']['']['medium']))
10783 $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
10785 if (isset($content['attribs']['']['samplingrate']))
10787 $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
10789 if (isset($content['attribs']['']['type']))
10791 $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10793 if (isset($content['attribs']['']['width']))
10795 $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
10797 $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10799 // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
10802 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
10804 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
10806 $caption_type = null;
10807 $caption_lang = null;
10808 $caption_startTime = null;
10809 $caption_endTime = null;
10810 $caption_text = null;
10811 if (isset($caption['attribs']['']['type']))
10813 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10815 if (isset($caption['attribs']['']['lang']))
10817 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10819 if (isset($caption['attribs']['']['start']))
10821 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10823 if (isset($caption['attribs']['']['end']))
10825 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10827 if (isset($caption['data']))
10829 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10831 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10833 if (is_array($captions))
10835 $captions = array_values(array_unique($captions));
10838 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
10840 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
10842 $caption_type = null;
10843 $caption_lang = null;
10844 $caption_startTime = null;
10845 $caption_endTime = null;
10846 $caption_text = null;
10847 if (isset($caption['attribs']['']['type']))
10849 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10851 if (isset($caption['attribs']['']['lang']))
10853 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10855 if (isset($caption['attribs']['']['start']))
10857 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10859 if (isset($caption['attribs']['']['end']))
10861 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10863 if (isset($caption['data']))
10865 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10867 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10869 if (is_array($captions))
10871 $captions = array_values(array_unique($captions));
10876 $captions = $captions_parent;
10880 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
10882 foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
10887 if (isset($category['data']))
10889 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10891 if (isset($category['attribs']['']['scheme']))
10893 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10897 $scheme = 'http://search.yahoo.com/mrss/category_schema';
10899 if (isset($category['attribs']['']['label']))
10901 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10903 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
10906 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
10908 foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
10913 if (isset($category['data']))
10915 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10917 if (isset($category['attribs']['']['scheme']))
10919 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10923 $scheme = 'http://search.yahoo.com/mrss/category_schema';
10925 if (isset($category['attribs']['']['label']))
10927 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10929 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
10932 if (is_array($categories) && is_array($categories_parent))
10934 $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
10936 elseif (is_array($categories))
10938 $categories = array_values(array_unique($categories));
10940 elseif (is_array($categories_parent))
10942 $categories = array_values(array_unique($categories_parent));
10946 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
10948 $copyright_url = null;
10949 $copyright_label = null;
10950 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
10952 $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10954 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
10956 $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10958 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10960 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
10962 $copyright_url = null;
10963 $copyright_label = null;
10964 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
10966 $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10968 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
10970 $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10972 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10976 $copyrights = $copyrights_parent;
10980 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
10982 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
10984 $credit_role = null;
10985 $credit_scheme = null;
10986 $credit_name = null;
10987 if (isset($credit['attribs']['']['role']))
10989 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
10991 if (isset($credit['attribs']['']['scheme']))
10993 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10997 $credit_scheme = 'urn:ebu';
10999 if (isset($credit['data']))
11001 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11003 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
11005 if (is_array($credits))
11007 $credits = array_values(array_unique($credits));
11010 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
11012 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
11014 $credit_role = null;
11015 $credit_scheme = null;
11016 $credit_name = null;
11017 if (isset($credit['attribs']['']['role']))
11019 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
11021 if (isset($credit['attribs']['']['scheme']))
11023 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11027 $credit_scheme = 'urn:ebu';
11029 if (isset($credit['data']))
11031 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11033 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
11035 if (is_array($credits))
11037 $credits = array_values(array_unique($credits));
11042 $credits = $credits_parent;
11046 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
11048 $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11050 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
11052 $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11056 $description = $description_parent;
11060 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
11062 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
11066 if (isset($hash['data']))
11068 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11070 if (isset($hash['attribs']['']['algo']))
11072 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
11078 $hashes[] = $algo.':'.$value;
11080 if (is_array($hashes))
11082 $hashes = array_values(array_unique($hashes));
11085 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
11087 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
11091 if (isset($hash['data']))
11093 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11095 if (isset($hash['attribs']['']['algo']))
11097 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
11103 $hashes[] = $algo.':'.$value;
11105 if (is_array($hashes))
11107 $hashes = array_values(array_unique($hashes));
11112 $hashes = $hashes_parent;
11116 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
11118 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
11120 $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
11121 foreach ($temp as $word)
11123 $keywords[] = trim($word);
11127 if (is_array($keywords))
11129 $keywords = array_values(array_unique($keywords));
11132 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
11134 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
11136 $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
11137 foreach ($temp as $word)
11139 $keywords[] = trim($word);
11143 if (is_array($keywords))
11145 $keywords = array_values(array_unique($keywords));
11150 $keywords = $keywords_parent;
11154 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11156 $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11158 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11160 $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11164 $player = $player_parent;
11168 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
11170 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
11172 $rating_scheme = null;
11173 $rating_value = null;
11174 if (isset($rating['attribs']['']['scheme']))
11176 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11180 $rating_scheme = 'urn:simple';
11182 if (isset($rating['data']))
11184 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11186 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
11188 if (is_array($ratings))
11190 $ratings = array_values(array_unique($ratings));
11193 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
11195 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
11197 $rating_scheme = null;
11198 $rating_value = null;
11199 if (isset($rating['attribs']['']['scheme']))
11201 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11205 $rating_scheme = 'urn:simple';
11207 if (isset($rating['data']))
11209 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11211 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
11213 if (is_array($ratings))
11215 $ratings = array_values(array_unique($ratings));
11220 $ratings = $ratings_parent;
11224 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
11226 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
11228 $restriction_relationship = null;
11229 $restriction_type = null;
11230 $restriction_value = null;
11231 if (isset($restriction['attribs']['']['relationship']))
11233 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
11235 if (isset($restriction['attribs']['']['type']))
11237 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11239 if (isset($restriction['data']))
11241 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11243 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
11245 if (is_array($restrictions))
11247 $restrictions = array_values(array_unique($restrictions));
11250 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
11252 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
11254 $restriction_relationship = null;
11255 $restriction_type = null;
11256 $restriction_value = null;
11257 if (isset($restriction['attribs']['']['relationship']))
11259 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
11261 if (isset($restriction['attribs']['']['type']))
11263 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11265 if (isset($restriction['data']))
11267 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11269 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
11271 if (is_array($restrictions))
11273 $restrictions = array_values(array_unique($restrictions));
11278 $restrictions = $restrictions_parent;
11282 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
11284 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
11286 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11288 if (is_array($thumbnails))
11290 $thumbnails = array_values(array_unique($thumbnails));
11293 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
11295 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
11297 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11299 if (is_array($thumbnails))
11301 $thumbnails = array_values(array_unique($thumbnails));
11306 $thumbnails = $thumbnails_parent;
11310 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
11312 $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11314 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
11316 $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11320 $title = $title_parent;
11323 $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));
11329 // If we have standalone media:content tags, loop through them.
11330 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
11332 foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
11334 if (isset($content['attribs']['']['url']) || isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11340 $expression = null;
11343 $javascript = null;
11347 $samplingrate = null;
11354 $categories = null;
11355 $copyrights = null;
11357 $description = null;
11362 $restrictions = null;
11363 $thumbnails = null;
11366 // Start checking the attributes of media:content
11367 if (isset($content['attribs']['']['bitrate']))
11369 $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
11371 if (isset($content['attribs']['']['channels']))
11373 $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
11375 if (isset($content['attribs']['']['duration']))
11377 $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
11381 $duration = $duration_parent;
11383 if (isset($content['attribs']['']['expression']))
11385 $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
11387 if (isset($content['attribs']['']['framerate']))
11389 $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
11391 if (isset($content['attribs']['']['height']))
11393 $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
11395 if (isset($content['attribs']['']['lang']))
11397 $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
11399 if (isset($content['attribs']['']['fileSize']))
11401 $length = ceil($content['attribs']['']['fileSize']);
11403 if (isset($content['attribs']['']['medium']))
11405 $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
11407 if (isset($content['attribs']['']['samplingrate']))
11409 $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
11411 if (isset($content['attribs']['']['type']))
11413 $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11415 if (isset($content['attribs']['']['width']))
11417 $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
11419 if (isset($content['attribs']['']['url']))
11421 $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11423 // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
11426 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
11428 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
11430 $caption_type = null;
11431 $caption_lang = null;
11432 $caption_startTime = null;
11433 $caption_endTime = null;
11434 $caption_text = null;
11435 if (isset($caption['attribs']['']['type']))
11437 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11439 if (isset($caption['attribs']['']['lang']))
11441 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
11443 if (isset($caption['attribs']['']['start']))
11445 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
11447 if (isset($caption['attribs']['']['end']))
11449 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
11451 if (isset($caption['data']))
11453 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11455 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
11457 if (is_array($captions))
11459 $captions = array_values(array_unique($captions));
11464 $captions = $captions_parent;
11468 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
11470 foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
11475 if (isset($category['data']))
11477 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11479 if (isset($category['attribs']['']['scheme']))
11481 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11485 $scheme = 'http://search.yahoo.com/mrss/category_schema';
11487 if (isset($category['attribs']['']['label']))
11489 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
11491 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
11494 if (is_array($categories) && is_array($categories_parent))
11496 $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
11498 elseif (is_array($categories))
11500 $categories = array_values(array_unique($categories));
11502 elseif (is_array($categories_parent))
11504 $categories = array_values(array_unique($categories_parent));
11508 $categories = null;
11512 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
11514 $copyright_url = null;
11515 $copyright_label = null;
11516 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
11518 $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
11520 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
11522 $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11524 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
11528 $copyrights = $copyrights_parent;
11532 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
11534 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
11536 $credit_role = null;
11537 $credit_scheme = null;
11538 $credit_name = null;
11539 if (isset($credit['attribs']['']['role']))
11541 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
11543 if (isset($credit['attribs']['']['scheme']))
11545 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11549 $credit_scheme = 'urn:ebu';
11551 if (isset($credit['data']))
11553 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11555 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
11557 if (is_array($credits))
11559 $credits = array_values(array_unique($credits));
11564 $credits = $credits_parent;
11568 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
11570 $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11574 $description = $description_parent;
11578 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
11580 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
11584 if (isset($hash['data']))
11586 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11588 if (isset($hash['attribs']['']['algo']))
11590 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
11596 $hashes[] = $algo.':'.$value;
11598 if (is_array($hashes))
11600 $hashes = array_values(array_unique($hashes));
11605 $hashes = $hashes_parent;
11609 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
11611 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
11613 $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
11614 foreach ($temp as $word)
11616 $keywords[] = trim($word);
11620 if (is_array($keywords))
11622 $keywords = array_values(array_unique($keywords));
11627 $keywords = $keywords_parent;
11631 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11633 $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11637 $player = $player_parent;
11641 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
11643 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
11645 $rating_scheme = null;
11646 $rating_value = null;
11647 if (isset($rating['attribs']['']['scheme']))
11649 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11653 $rating_scheme = 'urn:simple';
11655 if (isset($rating['data']))
11657 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11659 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
11661 if (is_array($ratings))
11663 $ratings = array_values(array_unique($ratings));
11668 $ratings = $ratings_parent;
11672 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
11674 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
11676 $restriction_relationship = null;
11677 $restriction_type = null;
11678 $restriction_value = null;
11679 if (isset($restriction['attribs']['']['relationship']))
11681 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
11683 if (isset($restriction['attribs']['']['type']))
11685 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11687 if (isset($restriction['data']))
11689 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11691 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
11693 if (is_array($restrictions))
11695 $restrictions = array_values(array_unique($restrictions));
11700 $restrictions = $restrictions_parent;
11704 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
11706 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
11708 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11710 if (is_array($thumbnails))
11712 $thumbnails = array_values(array_unique($thumbnails));
11717 $thumbnails = $thumbnails_parent;
11721 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
11723 $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11727 $title = $title_parent;
11730 $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));
11735 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
11737 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
11743 $expression = null;
11746 $javascript = null;
11750 $samplingrate = null;
11755 $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
11756 if (isset($link['attribs']['']['type']))
11758 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11760 if (isset($link['attribs']['']['length']))
11762 $length = ceil($link['attribs']['']['length']);
11765 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11766 $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));
11770 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
11772 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
11778 $expression = null;
11781 $javascript = null;
11785 $samplingrate = null;
11790 $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
11791 if (isset($link['attribs']['']['type']))
11793 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11795 if (isset($link['attribs']['']['length']))
11797 $length = ceil($link['attribs']['']['length']);
11800 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11801 $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));
11805 if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure'))
11807 if (isset($enclosure[0]['attribs']['']['url']))
11813 $expression = null;
11816 $javascript = null;
11820 $samplingrate = null;
11825 $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
11826 if (isset($enclosure[0]['attribs']['']['type']))
11828 $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11830 if (isset($enclosure[0]['attribs']['']['length']))
11832 $length = ceil($enclosure[0]['attribs']['']['length']);
11835 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11836 $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 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))
11842 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11843 $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));
11846 $this->data['enclosures'] = array_values(array_unique($this->data['enclosures']));
11848 if (!empty($this->data['enclosures']))
11850 return $this->data['enclosures'];
11859 * Get the latitude coordinates for the item
11861 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
11863 * Uses `<geo:lat>` or `<georss:point>`
11866 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
11867 * @link http://www.georss.org/ GeoRSS
11868 * @return string|null
11870 public function get_latitude()
11872 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
11874 return (float) $return[0]['data'];
11876 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))
11878 return (float) $match[1];
11887 * Get the longitude coordinates for the item
11889 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
11891 * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
11894 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
11895 * @link http://www.georss.org/ GeoRSS
11896 * @return string|null
11898 public function get_longitude()
11900 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
11902 return (float) $return[0]['data'];
11904 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
11906 return (float) $return[0]['data'];
11908 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))
11910 return (float) $match[2];
11919 * Get the `<atom:source>` for the item
11922 * @return SimplePie_Source|null
11924 public function get_source()
11926 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
11928 return $this->registry->create('Source', array($this, $return[0]));
11938 * Used for feed auto-discovery
11941 * This class can be overloaded with {@see SimplePie::set_locator_class()}
11943 * @package SimplePie
11945 class SimplePie_Locator
11950 var $local = array();
11951 var $elsewhere = array();
11952 var $cached_entities = array();
11955 var $base_location = 0;
11956 var $checked_feeds = 0;
11957 var $max_checked_feeds = 10;
11958 protected $registry;
11960 public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10)
11962 $this->file = $file;
11963 $this->useragent = $useragent;
11964 $this->timeout = $timeout;
11965 $this->max_checked_feeds = $max_checked_feeds;
11967 if (class_exists('DOMDocument'))
11969 $this->dom = new DOMDocument();
11971 set_error_handler(array('SimplePie_Misc', 'silence_errors'));
11972 $this->dom->loadHTML($this->file->body);
11973 restore_error_handler();
11981 public function set_registry(SimplePie_Registry $registry)
11983 $this->registry = $registry;
11986 public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
11988 if ($this->is_feed($this->file))
11990 return $this->file;
11993 if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
11995 $sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file));
11996 if ($sniffer->get_type() !== 'text/html')
12002 if ($type & ~SIMPLEPIE_LOCATOR_NONE)
12007 if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
12009 return $working[0];
12012 if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
12014 if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
12019 if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
12024 if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
12029 if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
12037 public function is_feed($file)
12039 if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
12041 $sniffer = $this->registry->create('Content_Type_Sniffer', array($file));
12042 $sniffed = $sniffer->get_type();
12043 if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
12052 elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
12062 public function get_base()
12064 if ($this->dom === null)
12066 throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
12068 $this->http_base = $this->file->url;
12069 $this->base = $this->http_base;
12070 $elements = $this->dom->getElementsByTagName('base');
12071 foreach ($elements as $element)
12073 if ($element->hasAttribute('href'))
12075 $base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base));
12076 if ($base === false)
12080 $this->base = $base;
12081 $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0;
12087 public function autodiscovery()
12091 $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds));
12092 $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds));
12093 $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds));
12095 if (!empty($feeds))
12097 return array_values($feeds);
12105 protected function search_elements_by_tag($name, &$done, $feeds)
12107 if ($this->dom === null)
12109 throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
12112 $links = $this->dom->getElementsByTagName($name);
12113 foreach ($links as $link)
12115 if ($this->checked_feeds === $this->max_checked_feeds)
12119 if ($link->hasAttribute('href') && $link->hasAttribute('rel'))
12121 $rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel')))));
12122 $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1;
12124 if ($this->base_location < $line)
12126 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
12130 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
12132 if ($href === false)
12137 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]))
12139 $this->checked_feeds++;
12141 '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',
12143 $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent));
12144 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))
12146 $feeds[$href] = $feed;
12156 public function get_links()
12158 if ($this->dom === null)
12160 throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
12163 $links = $this->dom->getElementsByTagName('a');
12164 foreach ($links as $link)
12166 if ($link->hasAttribute('href'))
12168 $href = trim($link->getAttribute('href'));
12169 $parsed = $this->registry->call('Misc', 'parse_url', array($href));
12170 if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
12172 if ($this->base_location < $link->getLineNo())
12174 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
12178 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
12180 if ($href === false)
12185 $current = $this->registry->call('Misc', 'parse_url', array($this->file->url));
12187 if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
12189 $this->local[] = $href;
12193 $this->elsewhere[] = $href;
12198 $this->local = array_unique($this->local);
12199 $this->elsewhere = array_unique($this->elsewhere);
12200 if (!empty($this->local) || !empty($this->elsewhere))
12207 public function extension(&$array)
12209 foreach ($array as $key => $value)
12211 if ($this->checked_feeds === $this->max_checked_feeds)
12215 if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
12217 $this->checked_feeds++;
12220 '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',
12222 $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent));
12223 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))
12229 unset($array[$key]);
12236 public function body(&$array)
12238 foreach ($array as $key => $value)
12240 if ($this->checked_feeds === $this->max_checked_feeds)
12244 if (preg_match('/(rss|rdf|atom|xml)/i', $value))
12246 $this->checked_feeds++;
12248 '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',
12250 $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent));
12251 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))
12257 unset($array[$key]);
12266 * Miscellanous utilities
12268 * @package SimplePie
12270 class SimplePie_Misc
12272 public static function time_hms($seconds)
12276 $hours = floor($seconds / 3600);
12277 $remainder = $seconds % 3600;
12280 $time .= $hours.':';
12283 $minutes = floor($remainder / 60);
12284 $seconds = $remainder % 60;
12285 if ($minutes < 10 && $hours > 0)
12287 $minutes = '0' . $minutes;
12291 $seconds = '0' . $seconds;
12294 $time .= $minutes.':';
12300 public static function absolutize_url($relative, $base)
12302 $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
12303 if ($iri === false)
12307 return $iri->get_uri();
12311 * Get a HTML/XML element from a HTML string
12313 * @deprecated Use DOMDocument instead (parsing HTML with regex is bad!)
12314 * @param string $realname Element name (including namespace prefix if applicable)
12315 * @param string $string HTML document
12318 public static function get_element($realname, $string)
12321 $name = preg_quote($realname, '/');
12322 if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
12324 for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
12326 $return[$i]['tag'] = $realname;
12327 $return[$i]['full'] = $matches[$i][0][0];
12328 $return[$i]['offset'] = $matches[$i][0][1];
12329 if (strlen($matches[$i][3][0]) <= 2)
12331 $return[$i]['self_closing'] = true;
12335 $return[$i]['self_closing'] = false;
12336 $return[$i]['content'] = $matches[$i][4][0];
12338 $return[$i]['attribs'] = array();
12339 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))
12341 for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
12343 if (count($attribs[$j]) === 2)
12345 $attribs[$j][2] = $attribs[$j][1];
12347 $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
12355 public static function element_implode($element)
12357 $full = "<$element[tag]";
12358 foreach ($element['attribs'] as $key => $value)
12360 $key = strtolower($key);
12361 $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
12363 if ($element['self_closing'])
12369 $full .= ">$element[content]</$element[tag]>";
12374 public static function error($message, $level, $file, $line)
12376 if ((ini_get('error_reporting') & $level) > 0)
12381 $note = 'PHP Error';
12383 case E_USER_WARNING:
12384 $note = 'PHP Warning';
12386 case E_USER_NOTICE:
12387 $note = 'PHP Notice';
12390 $note = 'Unknown Error';
12395 if (!function_exists('error_log'))
12397 $log_error = false;
12400 $log_file = @ini_get('error_log');
12401 if (!empty($log_file) && ('syslog' !== $log_file) && !@is_writable($log_file))
12403 $log_error = false;
12408 @error_log("$note: $message in $file on line $line", 0);
12415 public static function fix_protocol($url, $http = 1)
12417 $url = SimplePie_Misc::normalize_url($url);
12418 $parsed = SimplePie_Misc::parse_url($url);
12419 if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https')
12421 return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http);
12424 if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url))
12426 return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http);
12429 if ($http === 2 && $parsed['scheme'] !== '')
12431 return "feed:$url";
12433 elseif ($http === 3 && strtolower($parsed['scheme']) === 'http')
12435 return substr_replace($url, 'podcast', 0, 4);
12437 elseif ($http === 4 && strtolower($parsed['scheme']) === 'http')
12439 return substr_replace($url, 'itpc', 0, 4);
12447 public static function parse_url($url)
12449 $iri = new SimplePie_IRI($url);
12451 'scheme' => (string) $iri->scheme,
12452 'authority' => (string) $iri->authority,
12453 'path' => (string) $iri->path,
12454 'query' => (string) $iri->query,
12455 'fragment' => (string) $iri->fragment
12459 public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
12461 $iri = new SimplePie_IRI('');
12462 $iri->scheme = $scheme;
12463 $iri->authority = $authority;
12464 $iri->path = $path;
12465 $iri->query = $query;
12466 $iri->fragment = $fragment;
12467 return $iri->get_uri();
12470 public static function normalize_url($url)
12472 $iri = new SimplePie_IRI($url);
12473 return $iri->get_uri();
12476 public static function percent_encoding_normalization($match)
12478 $integer = hexdec($match[1]);
12479 if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E)
12481 return chr($integer);
12485 return strtoupper($match[0]);
12490 * Converts a Windows-1252 encoded string to a UTF-8 encoded string
12493 * @param string $string Windows-1252 encoded string
12494 * @return string UTF-8 encoded string
12496 public static function windows_1252_to_utf8($string)
12498 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");
12500 return strtr($string, $convert_table);
12504 * Change a string from one encoding to another
12506 * @param string $data Raw data in $input encoding
12507 * @param string $input Encoding of $data
12508 * @param string $output Encoding you want
12509 * @return string|boolean False if we can't convert it
12511 public static function change_encoding($data, $input, $output)
12513 $input = SimplePie_Misc::encoding($input);
12514 $output = SimplePie_Misc::encoding($output);
12516 // We fail to fail on non US-ASCII bytes
12517 if ($input === 'US-ASCII')
12519 static $non_ascii_octects = '';
12520 if (!$non_ascii_octects)
12522 for ($i = 0x80; $i <= 0xFF; $i++)
12524 $non_ascii_octects .= chr($i);
12527 $data = substr($data, 0, strcspn($data, $non_ascii_octects));
12530 // This is first, as behaviour of this is completely predictable
12531 if ($input === 'windows-1252' && $output === 'UTF-8')
12533 return SimplePie_Misc::windows_1252_to_utf8($data);
12535 // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported).
12536 elseif (function_exists('mb_convert_encoding') && ($return = SimplePie_Misc::change_encoding_mbstring($data, $input, $output)))
12540 // This is last, as behaviour of this varies with OS userland and PHP version
12541 elseif (function_exists('iconv') && ($return = SimplePie_Misc::change_encoding_iconv($data, $input, $output)))
12545 // If we can't do anything, just fail
12552 protected static function change_encoding_mbstring($data, $input, $output)
12554 if ($input === 'windows-949')
12558 if ($output === 'windows-949')
12560 $output = 'EUC-KR';
12562 if ($input === 'Windows-31J')
12566 if ($output === 'Windows-31J')
12571 // Check that the encoding is supported
12572 if (@mb_convert_encoding("\x80", 'UTF-16BE', $input) === "\x00\x80")
12576 if (!in_array($input, mb_list_encodings()))
12581 // Let's do some conversion
12582 if ($return = @mb_convert_encoding($data, $output, $input))
12590 protected static function change_encoding_iconv($data, $input, $output)
12592 return @iconv($input, $output, $data);
12596 * Normalize an encoding name
12598 * This is automatically generated by create.php
12600 * To generate it, run `php create.php` on the command line, and copy the
12601 * output to replace this function.
12603 * @param string $charset Character set to standardise
12604 * @return string Standardised name
12606 public static function encoding($charset)
12608 // Normalization from UTS #22
12609 switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset)))
12611 case 'adobestandardencoding':
12612 case 'csadobestandardencoding':
12613 return 'Adobe-Standard-Encoding';
12615 case 'adobesymbolencoding':
12617 return 'Adobe-Symbol-Encoding';
12621 return 'Amiga-1251';
12623 case 'ansix31101983':
12624 case 'csat5001983':
12625 case 'csiso99naplps':
12628 return 'ANSI_X3.110-1983';
12632 case 'csiso89asmo449':
12642 return 'Big5-HKSCS';
12653 case 'csiso4unitedkingdom':
12661 case 'csiso47bsviewdata':
12663 return 'BS_viewdata';
12671 case 'csaz243419851':
12672 case 'csiso121canadian1':
12675 return 'CSA_Z243.4-1985-1';
12678 case 'csaz243419852':
12679 case 'csiso122canadian2':
12682 return 'CSA_Z243.4-1985-2';
12684 case 'csaz24341985gr':
12685 case 'csiso123csaz24341985gr':
12687 return 'CSA_Z243.4-1985-gr';
12689 case 'csiso139csn369103':
12692 return 'CSN_369103';
12699 case 'csiso21german':
12704 return 'DIN_66003';
12710 case 'csiso646danish':
12716 case 'csibmebcdicatde':
12718 return 'EBCDIC-AT-DE';
12720 case 'csebcdicatdea':
12721 case 'ebcdicatdea':
12722 return 'EBCDIC-AT-DE-A';
12724 case 'csebcdiccafr':
12726 return 'EBCDIC-CA-FR';
12728 case 'csebcdicdkno':
12730 return 'EBCDIC-DK-NO';
12732 case 'csebcdicdknoa':
12733 case 'ebcdicdknoa':
12734 return 'EBCDIC-DK-NO-A';
12738 return 'EBCDIC-ES';
12740 case 'csebcdicesa':
12742 return 'EBCDIC-ES-A';
12744 case 'csebcdicess':
12746 return 'EBCDIC-ES-S';
12748 case 'csebcdicfise':
12750 return 'EBCDIC-FI-SE';
12752 case 'csebcdicfisea':
12753 case 'ebcdicfisea':
12754 return 'EBCDIC-FI-SE-A';
12758 return 'EBCDIC-FR';
12762 return 'EBCDIC-IT';
12766 return 'EBCDIC-PT';
12770 return 'EBCDIC-UK';
12774 return 'EBCDIC-US';
12776 case 'csiso111ecmacyrillic':
12777 case 'ecmacyrillic':
12780 return 'ECMA-cyrillic';
12782 case 'csiso17spanish':
12788 case 'csiso85spanish2':
12794 case 'cseucpkdfmtjapanese':
12796 case 'extendedunixcodepackedformatforjapanese':
12799 case 'cseucfixwidjapanese':
12800 case 'extendedunixcodefixedwidthforjapanese':
12801 return 'Extended_UNIX_Code_Fixed_Width_for_Japanese';
12809 case 'csiso58gb231280':
12819 case 'csiso57gb1988':
12823 return 'GB_1988-80';
12825 case 'csiso153gost1976874':
12826 case 'gost1976874':
12829 return 'GOST_19768-74';
12832 case 'csiso150greekccitt':
12835 return 'greek-ccitt';
12837 case 'csiso88greek7':
12842 case 'csiso18greek7old':
12845 return 'greek7-old';
12847 case 'cshpdesktop':
12849 return 'HP-DeskTop';
12861 return 'HP-Pi-font';
12867 return 'hp-roman8';
12870 return 'HZ-GB-2312';
12872 case 'csibmsymbols':
12874 return 'IBM-Symbols';
12951 case 'ebcdicjpkana':
12963 case 'ebcdiccpar1':
12981 case 'cspc8codepage437':
12993 case 'cspc775baltic':
12999 case 'cspc850multilingual':
13030 case 'pcmultilingual850euro':
13048 case 'cspc862latinhebrew':
13090 case 'ebcdiccproece':
13103 case 'ebcdiccyrillic':
13131 case 'ebcdiccpar2':
13137 case 'ebcdiclatin9euro':
13151 case 'ebcdicus37euro':
13157 case 'ebcdicde273euro':
13163 case 'ebcdicdk277euro':
13164 case 'ebcdicno277euro':
13170 case 'ebcdicfi278euro':
13171 case 'ebcdicse278euro':
13177 case 'ebcdicit280euro':
13183 case 'ebcdices284euro':
13189 case 'ebcdicgb285euro':
13195 case 'ebcdicfr297euro':
13201 case 'ebcdicinternational500euro':
13207 case 'ebcdicis871euro':
13211 case 'csiso143iecp271':
13214 return 'IEC_P27-1';
13216 case 'csiso49inis':
13221 case 'csiso50inis8':
13226 case 'csiso51iniscyrillic':
13227 case 'iniscyrillic':
13229 return 'INIS-cyrillic';
13231 case 'csinvariant':
13233 return 'INVARIANT';
13236 return 'ISO-2022-CN';
13238 case 'iso2022cnext':
13239 return 'ISO-2022-CN-EXT';
13241 case 'csiso2022jp':
13243 return 'ISO-2022-JP';
13245 case 'csiso2022jp2':
13247 return 'ISO-2022-JP-2';
13249 case 'csiso2022kr':
13251 return 'ISO-2022-KR';
13253 case 'cswindows30latin1':
13254 case 'iso88591windows30latin1':
13255 return 'ISO-8859-1-Windows-3.0-Latin-1';
13257 case 'cswindows31latin1':
13258 case 'iso88591windows31latin1':
13259 return 'ISO-8859-1-Windows-3.1-Latin-1';
13261 case 'csisolatin2':
13263 case 'iso885921987':
13267 return 'ISO-8859-2';
13269 case 'cswindows31latin2':
13270 case 'iso88592windowslatin2':
13271 return 'ISO-8859-2-Windows-Latin-2';
13273 case 'csisolatin3':
13275 case 'iso885931988':
13279 return 'ISO-8859-3';
13281 case 'csisolatin4':
13283 case 'iso885941988':
13287 return 'ISO-8859-4';
13289 case 'csisolatincyrillic':
13292 case 'iso885951988':
13294 return 'ISO-8859-5';
13298 case 'csisolatinarabic':
13301 case 'iso885961987':
13303 return 'ISO-8859-6';
13305 case 'csiso88596e':
13307 return 'ISO-8859-6-E';
13309 case 'csiso88596i':
13311 return 'ISO-8859-6-I';
13313 case 'csisolatingreek':
13319 case 'iso885971987':
13321 return 'ISO-8859-7';
13323 case 'csisolatinhebrew':
13326 case 'iso885981988':
13328 return 'ISO-8859-8';
13330 case 'csiso88598e':
13332 return 'ISO-8859-8-E';
13334 case 'csiso88598i':
13336 return 'ISO-8859-8-I';
13338 case 'cswindows31latin5':
13339 case 'iso88599windowslatin5':
13340 return 'ISO-8859-9-Windows-Latin-5';
13342 case 'csisolatin6':
13344 case 'iso8859101992':
13348 return 'ISO-8859-10';
13351 return 'ISO-8859-13';
13354 case 'iso8859141998':
13359 return 'ISO-8859-14';
13363 return 'ISO-8859-15';
13366 case 'iso8859162001':
13370 return 'ISO-8859-16';
13373 return 'ISO-10646-J-1';
13376 case 'iso10646ucs2':
13377 return 'ISO-10646-UCS-2';
13380 case 'iso10646ucs4':
13381 return 'ISO-10646-UCS-4';
13383 case 'csunicodeascii':
13384 case 'iso10646ucsbasic':
13385 return 'ISO-10646-UCS-Basic';
13387 case 'csunicodelatin1':
13389 case 'iso10646unicodelatin1':
13390 return 'ISO-10646-Unicode-Latin1';
13392 case 'csiso10646utf1':
13393 case 'iso10646utf1':
13394 return 'ISO-10646-UTF-1';
13396 case 'csiso115481':
13398 case 'isotr115481':
13399 return 'ISO-11548-1';
13403 return 'iso-ir-90';
13405 case 'csunicodeibm1261':
13406 case 'isounicodeibm1261':
13407 return 'ISO-Unicode-IBM-1261';
13409 case 'csunicodeibm1264':
13410 case 'isounicodeibm1264':
13411 return 'ISO-Unicode-IBM-1264';
13413 case 'csunicodeibm1265':
13414 case 'isounicodeibm1265':
13415 return 'ISO-Unicode-IBM-1265';
13417 case 'csunicodeibm1268':
13418 case 'isounicodeibm1268':
13419 return 'ISO-Unicode-IBM-1268';
13421 case 'csunicodeibm1276':
13422 case 'isounicodeibm1276':
13423 return 'ISO-Unicode-IBM-1276';
13425 case 'csiso646basic1983':
13426 case 'iso646basic1983':
13428 return 'ISO_646.basic:1983';
13430 case 'csiso2intlrefversion':
13432 case 'iso646irv1983':
13434 return 'ISO_646.irv:1983';
13438 case 'iso20331983':
13440 return 'ISO_2033-1983';
13442 case 'csiso5427cyrillic':
13447 case 'iso5427cyrillic1981':
13448 case 'iso54271981':
13450 return 'ISO_5427:1981';
13452 case 'csiso5428greek':
13453 case 'iso54281980':
13455 return 'ISO_5428:1980';
13457 case 'csiso6937add':
13460 return 'ISO_6937-2-25';
13462 case 'csisotextcomm':
13463 case 'iso69372add':
13465 return 'ISO_6937-2-add';
13467 case 'csiso8859supp':
13468 case 'iso8859supp':
13471 return 'ISO_8859-supp';
13473 case 'csiso10367box':
13474 case 'iso10367box':
13476 return 'ISO_10367-box';
13478 case 'csiso15italian':
13484 case 'csiso13jisc6220jp':
13486 case 'jisc62201969':
13487 case 'jisc62201969jp':
13490 return 'JIS_C6220-1969-jp';
13492 case 'csiso14jisc6220ro':
13495 case 'jisc62201969ro':
13497 return 'JIS_C6220-1969-ro';
13499 case 'csiso42jisc62261978':
13501 case 'jisc62261978':
13502 return 'JIS_C6226-1978';
13504 case 'csiso87jisx208':
13506 case 'jisc62261983':
13507 case 'jisx2081983':
13509 return 'JIS_C6226-1983';
13511 case 'csiso91jisc62291984a':
13513 case 'jisc62291984a':
13515 return 'JIS_C6229-1984-a';
13517 case 'csiso92jisc62991984b':
13518 case 'iso646jpocrb':
13520 case 'jisc62291984b':
13522 return 'JIS_C6229-1984-b';
13524 case 'csiso93jis62291984badd':
13526 case 'jisc62291984badd':
13528 return 'JIS_C6229-1984-b-add';
13530 case 'csiso94jis62291984hand':
13532 case 'jisc62291984hand':
13534 return 'JIS_C6229-1984-hand';
13536 case 'csiso95jis62291984handadd':
13538 case 'jisc62291984handadd':
13539 case 'jpocrhandadd':
13540 return 'JIS_C6229-1984-hand-add';
13542 case 'csiso96jisc62291984kana':
13544 case 'jisc62291984kana':
13545 return 'JIS_C6229-1984-kana';
13547 case 'csjisencoding':
13548 case 'jisencoding':
13549 return 'JIS_Encoding';
13551 case 'cshalfwidthkatakana':
13554 return 'JIS_X0201';
13556 case 'csiso159jisx2121990':
13558 case 'jisx2121990':
13560 return 'JIS_X0212-1990';
13562 case 'csiso141jusib1002':
13568 return 'JUS_I.B1.002';
13570 case 'csiso147macedonian':
13572 case 'jusib1003mac':
13574 return 'JUS_I.B1.003-mac';
13576 case 'csiso146serbian':
13578 case 'jusib1003serb':
13580 return 'JUS_I.B1.003-serb';
13582 case 'koi7switched':
13583 return 'KOI7-switched';
13600 case 'strk10482002':
13603 case 'csiso19latingreek':
13606 return 'latin-greek';
13608 case 'csiso27latingreek1':
13610 case 'latingreek1':
13611 return 'Latin-greek-1';
13613 case 'csiso158lap':
13617 return 'latin-lap';
13619 case 'csmacintosh':
13622 return 'macintosh';
13624 case 'csmicrosoftpublishing':
13625 case 'microsoftpublishing':
13626 return 'Microsoft-Publishing';
13636 case 'csiso86hungarian':
13641 return 'MSZ_7795.3';
13646 return 'NATS-DANO';
13648 case 'csnatsdanoadd':
13650 case 'natsdanoadd':
13651 return 'NATS-DANO-ADD';
13656 return 'NATS-SEFI';
13658 case 'csnatssefiadd':
13660 case 'natssefiadd':
13661 return 'NATS-SEFI-ADD';
13663 case 'csiso151cuba':
13668 return 'NC_NC00-10:81';
13670 case 'csiso69french':
13675 return 'NF_Z_62-010';
13677 case 'csiso25french':
13680 case 'nfz620101973':
13681 return 'NF_Z_62-010_(1973)';
13683 case 'csiso60danishnorwegian':
13684 case 'csiso60norwegian1':
13689 return 'NS_4551-1';
13691 case 'csiso61norwegian2':
13696 return 'NS_4551-2';
13698 case 'osdebcdicdf3irv':
13699 return 'OSD_EBCDIC_DF03_IRV';
13701 case 'osdebcdicdf41':
13702 return 'OSD_EBCDIC_DF04_1';
13704 case 'osdebcdicdf415':
13705 return 'OSD_EBCDIC_DF04_15';
13707 case 'cspc8danishnorwegian':
13708 case 'pc8danishnorwegian':
13709 return 'PC8-Danish-Norwegian';
13711 case 'cspc8turkish':
13713 return 'PC8-Turkish';
13715 case 'csiso16portuguese':
13721 case 'csiso84portuguese2':
13729 case 'cyrillicasian':
13737 case 'csiso10swedish':
13744 return 'SEN_850200_B';
13746 case 'csiso11swedishfornames':
13751 return 'SEN_850200_C';
13753 case 'csiso102t617bit':
13756 return 'T.61-7bit';
13758 case 'csiso103t618bit':
13762 return 'T.61-8bit';
13764 case 'csiso128t101g2':
13773 case 'csunicode11':
13775 return 'UNICODE-1-1';
13777 case 'csunicode11utf7':
13778 case 'unicode11utf7':
13779 return 'UNICODE-1-1-UTF-7';
13781 case 'csunknown8bit':
13782 case 'unknown8bit':
13783 return 'UNKNOWN-8BIT';
13785 case 'ansix341968':
13786 case 'ansix341986':
13791 case 'iso646irv1991':
13826 case 'csventurainternational':
13827 case 'venturainternational':
13828 return 'Ventura-International';
13830 case 'csventuramath':
13831 case 'venturamath':
13832 return 'Ventura-Math';
13834 case 'csventuraus':
13836 return 'Ventura-US';
13838 case 'csiso70videotexsupp1':
13840 case 'videotexsuppl':
13841 return 'videotex-suppl';
13852 case 'cswindows31j':
13856 return 'Windows-31J';
13860 return 'windows-874';
13863 case 'csksc56011987':
13868 case 'ksc56011987':
13869 case 'ksc56011989':
13871 return 'windows-949';
13873 case 'windows1250':
13874 return 'windows-1250';
13876 case 'windows1251':
13877 return 'windows-1251';
13880 case 'csisolatin1':
13883 case 'iso885911987':
13887 case 'windows1252':
13888 return 'windows-1252';
13890 case 'windows1253':
13891 return 'windows-1253';
13893 case 'csisolatin5':
13895 case 'iso885991989':
13899 case 'windows1254':
13900 return 'windows-1254';
13902 case 'windows1255':
13903 return 'windows-1255';
13905 case 'windows1256':
13906 return 'windows-1256';
13908 case 'windows1257':
13909 return 'windows-1257';
13911 case 'windows1258':
13912 return 'windows-1258';
13919 public static function get_curl_version()
13921 if (is_array($curl = curl_version()))
13923 $curl = $curl['version'];
13925 elseif (substr($curl, 0, 5) === 'curl/')
13927 $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
13929 elseif (substr($curl, 0, 8) === 'libcurl/')
13931 $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
13941 * Strip HTML comments
13943 * @param string $data Data to strip comments from
13944 * @return string Comment stripped string
13946 public static function strip_comments($data)
13949 while (($start = strpos($data, '<!--')) !== false)
13951 $output .= substr($data, 0, $start);
13952 if (($end = strpos($data, '-->', $start)) !== false)
13954 $data = substr_replace($data, '', 0, $end + 3);
13961 return $output . $data;
13964 public static function parse_date($dt)
13966 $parser = SimplePie_Parse_Date::get();
13967 return $parser->parse($dt);
13971 * Decode HTML entities
13973 * @deprecated Use DOMDocument instead
13974 * @param string $data Input data
13975 * @return string Output data
13977 public static function entities_decode($data)
13979 $decoder = new SimplePie_Decode_HTML_Entities($data);
13980 return $decoder->parse();
13984 * Remove RFC822 comments
13986 * @param string $data Data to strip comments from
13987 * @return string Comment stripped string
13989 public static function uncomment_rfc822($string)
13991 $string = (string) $string;
13993 $length = strlen($string);
13998 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
14000 $output .= substr($string, $position, $pos - $position);
14001 $position = $pos + 1;
14002 if ($string[$pos - 1] !== '\\')
14005 while ($depth && $position < $length)
14007 $position += strcspn($string, '()', $position);
14008 if ($string[$position - 1] === '\\')
14013 elseif (isset($string[$position]))
14015 switch ($string[$position])
14038 $output .= substr($string, $position);
14043 public static function parse_mime($mime)
14045 if (($pos = strpos($mime, ';')) === false)
14047 return trim($mime);
14051 return trim(substr($mime, 0, $pos));
14055 public static function atom_03_construct_type($attribs)
14057 if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64'))
14059 $mode = SIMPLEPIE_CONSTRUCT_BASE64;
14063 $mode = SIMPLEPIE_CONSTRUCT_NONE;
14065 if (isset($attribs['']['type']))
14067 switch (strtolower(trim($attribs['']['type'])))
14071 return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
14075 return SIMPLEPIE_CONSTRUCT_HTML | $mode;
14078 case 'application/xhtml+xml':
14079 return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
14082 return SIMPLEPIE_CONSTRUCT_NONE | $mode;
14087 return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
14091 public static function atom_10_construct_type($attribs)
14093 if (isset($attribs['']['type']))
14095 switch (strtolower(trim($attribs['']['type'])))
14098 return SIMPLEPIE_CONSTRUCT_TEXT;
14101 return SIMPLEPIE_CONSTRUCT_HTML;
14104 return SIMPLEPIE_CONSTRUCT_XHTML;
14107 return SIMPLEPIE_CONSTRUCT_NONE;
14110 return SIMPLEPIE_CONSTRUCT_TEXT;
14113 public static function atom_10_content_construct_type($attribs)
14115 if (isset($attribs['']['type']))
14117 $type = strtolower(trim($attribs['']['type']));
14121 return SIMPLEPIE_CONSTRUCT_TEXT;
14124 return SIMPLEPIE_CONSTRUCT_HTML;
14127 return SIMPLEPIE_CONSTRUCT_XHTML;
14129 if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/')
14131 return SIMPLEPIE_CONSTRUCT_NONE;
14135 return SIMPLEPIE_CONSTRUCT_BASE64;
14140 return SIMPLEPIE_CONSTRUCT_TEXT;
14144 public static function is_isegment_nz_nc($string)
14146 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);
14149 public static function space_seperated_tokens($string)
14151 $space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
14152 $string_length = strlen($string);
14154 $position = strspn($string, $space_characters);
14157 while ($position < $string_length)
14159 $len = strcspn($string, $space_characters, $position);
14160 $tokens[] = substr($string, $position, $len);
14162 $position += strspn($string, $space_characters, $position);
14169 * Converts a unicode codepoint to a UTF-8 character
14172 * @param int $codepoint Unicode codepoint
14173 * @return string UTF-8 character
14175 public static function codepoint_to_utf8($codepoint)
14177 $codepoint = (int) $codepoint;
14178 if ($codepoint < 0)
14182 else if ($codepoint <= 0x7f)
14184 return chr($codepoint);
14186 else if ($codepoint <= 0x7ff)
14188 return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
14190 else if ($codepoint <= 0xffff)
14192 return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
14194 else if ($codepoint <= 0x10ffff)
14196 return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
14200 // U+FFFD REPLACEMENT CHARACTER
14201 return "\xEF\xBF\xBD";
14206 * Similar to parse_str()
14208 * Returns an associative array of name/value pairs, where the value is an
14209 * array of values that have used the same name
14212 * @param string $str The input string.
14215 public static function parse_str($str)
14218 $str = explode('&', $str);
14220 foreach ($str as $section)
14222 if (strpos($section, '=') !== false)
14224 list($name, $value) = explode('=', $section, 2);
14225 $return[urldecode($name)][] = urldecode($value);
14229 $return[urldecode($section)][] = null;
14237 * Detect XML encoding, as per XML 1.0 Appendix F.1
14239 * @todo Add support for EBCDIC
14240 * @param string $data XML data
14241 * @param SimplePie_Registry $registry Class registry
14242 * @return array Possible encodings
14244 public static function xml_encoding($data, $registry)
14246 // UTF-32 Big Endian BOM
14247 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
14249 $encoding[] = 'UTF-32BE';
14251 // UTF-32 Little Endian BOM
14252 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
14254 $encoding[] = 'UTF-32LE';
14256 // UTF-16 Big Endian BOM
14257 elseif (substr($data, 0, 2) === "\xFE\xFF")
14259 $encoding[] = 'UTF-16BE';
14261 // UTF-16 Little Endian BOM
14262 elseif (substr($data, 0, 2) === "\xFF\xFE")
14264 $encoding[] = 'UTF-16LE';
14267 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
14269 $encoding[] = 'UTF-8';
14271 // UTF-32 Big Endian Without BOM
14272 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")
14274 if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
14276 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')));
14277 if ($parser->parse())
14279 $encoding[] = $parser->encoding;
14282 $encoding[] = 'UTF-32BE';
14284 // UTF-32 Little Endian Without BOM
14285 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")
14287 if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
14289 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')));
14290 if ($parser->parse())
14292 $encoding[] = $parser->encoding;
14295 $encoding[] = 'UTF-32LE';
14297 // UTF-16 Big Endian Without BOM
14298 elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C")
14300 if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
14302 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')));
14303 if ($parser->parse())
14305 $encoding[] = $parser->encoding;
14308 $encoding[] = 'UTF-16BE';
14310 // UTF-16 Little Endian Without BOM
14311 elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00")
14313 if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
14315 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')));
14316 if ($parser->parse())
14318 $encoding[] = $parser->encoding;
14321 $encoding[] = 'UTF-16LE';
14323 // US-ASCII (or superset)
14324 elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C")
14326 if ($pos = strpos($data, "\x3F\x3E"))
14328 $parser = $registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
14329 if ($parser->parse())
14331 $encoding[] = $parser->encoding;
14334 $encoding[] = 'UTF-8';
14336 // Fallback to UTF-8
14339 $encoding[] = 'UTF-8';
14344 public static function output_javascript()
14346 if (function_exists('ob_gzhandler'))
14348 ob_start('ob_gzhandler');
14350 header('Content-type: text/javascript; charset: UTF-8');
14351 header('Cache-Control: must-revalidate');
14352 header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
14354 function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
14355 if (placeholder != '') {
14356 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>');
14359 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>');
14363 function embed_flash(bgcolor, width, height, link, loop, type) {
14364 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>');
14367 function embed_flv(width, height, link, placeholder, loop, player) {
14368 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>');
14371 function embed_wmedia(width, height, link) {
14372 document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
14378 * Get the SimplePie build timestamp
14380 * Uses the git index if it exists, otherwise uses the modification time
14381 * of the newest file.
14383 public static function get_build()
14385 $root = dirname(dirname(__FILE__));
14386 if (file_exists($root . '/.git/index'))
14388 return filemtime($root . '/.git/index');
14390 elseif (file_exists($root . '/SimplePie'))
14393 foreach (glob($root . '/SimplePie/*.php') as $file)
14395 if (($mtime = filemtime($file)) > $time)
14402 elseif (file_exists(dirname(__FILE__) . '/Core.php'))
14404 return filemtime(dirname(__FILE__) . '/Core.php');
14408 return filemtime(__FILE__);
14413 * Format debugging information
14415 public static function debug(&$sp)
14417 $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n";
14418 $info .= 'PHP ' . PHP_VERSION . "\n";
14419 if ($sp->error() !== null)
14421 $info .= 'Error occurred: ' . $sp->error() . "\n";
14425 $info .= "No error found.\n";
14427 $info .= "Extensions:\n";
14428 $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml');
14429 foreach ($extensions as $ext)
14431 if (extension_loaded($ext))
14433 $info .= " $ext loaded\n";
14437 $info .= ' Version ' . PCRE_VERSION . "\n";
14440 $version = curl_version();
14441 $info .= ' Version ' . $version['version'] . "\n";
14444 $info .= ' Overloading: ' . mb_get_info('func_overload') . "\n";
14447 $info .= ' Version ' . ICONV_VERSION . "\n";
14450 $info .= ' Version ' . LIBXML_DOTTED_VERSION . "\n";
14456 $info .= " $ext not loaded\n";
14462 public static function silence_errors($num, $str)
14469 * Class to validate and to work with IPv6 addresses.
14471 * @package SimplePie
14473 * @copyright 2003-2005 The PHP Group
14474 * @license http://www.opensource.org/licenses/bsd-license.php
14475 * @link http://pear.php.net/package/Net_IPv6
14476 * @author Alexander Merz <alexander.merz@web.de>
14477 * @author elfrink at introweb dot nl
14478 * @author Josh Peck <jmp at joshpeck dot org>
14479 * @author Geoffrey Sneddon <geoffers@gmail.com>
14481 class SimplePie_Net_IPv6
14484 * Uncompresses an IPv6 address
14486 * RFC 4291 allows you to compress concecutive zero pieces in an address to
14487 * '::'. This method expects a valid IPv6 address and expands the '::' to
14488 * the required number of zero pieces.
14490 * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
14491 * ::1 -> 0:0:0:0:0:0:0:1
14493 * @author Alexander Merz <alexander.merz@web.de>
14494 * @author elfrink at introweb dot nl
14495 * @author Josh Peck <jmp at joshpeck dot org>
14496 * @copyright 2003-2005 The PHP Group
14497 * @license http://www.opensource.org/licenses/bsd-license.php
14498 * @param string $ip An IPv6 address
14499 * @return string The uncompressed IPv6 address
14501 public static function uncompress($ip)
14505 if (substr_count($ip, '::') === 1)
14507 list($ip1, $ip2) = explode('::', $ip);
14514 $c1 = substr_count($ip1, ':');
14522 $c2 = substr_count($ip2, ':');
14524 if (strpos($ip2, '.') !== false)
14529 if ($c1 === -1 && $c2 === -1)
14531 $ip = '0:0:0:0:0:0:0:0';
14534 else if ($c1 === -1)
14536 $fill = str_repeat('0:', 7 - $c2);
14537 $ip = str_replace('::', $fill, $ip);
14540 else if ($c2 === -1)
14542 $fill = str_repeat(':0', 7 - $c1);
14543 $ip = str_replace('::', $fill, $ip);
14548 $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
14549 $ip = str_replace('::', $fill, $ip);
14556 * Compresses an IPv6 address
14558 * RFC 4291 allows you to compress concecutive zero pieces in an address to
14559 * '::'. This method expects a valid IPv6 address and compresses consecutive
14560 * zero pieces to '::'.
14562 * Example: FF01:0:0:0:0:0:0:101 -> FF01::101
14563 * 0:0:0:0:0:0:0:1 -> ::1
14565 * @see uncompress()
14566 * @param string $ip An IPv6 address
14567 * @return string The compressed IPv6 address
14569 public static function compress($ip)
14571 // Prepare the IP to be compressed
14572 $ip = self::uncompress($ip);
14573 $ip_parts = self::split_v6_v4($ip);
14575 // Replace all leading zeros
14576 $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
14578 // Find bunches of zeros
14579 if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE))
14583 foreach ($matches[0] as $match)
14585 if (strlen($match[0]) > $max)
14587 $max = strlen($match[0]);
14592 $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
14595 if ($ip_parts[1] !== '')
14597 return implode(':', $ip_parts);
14601 return $ip_parts[0];
14606 * Splits an IPv6 address into the IPv6 and IPv4 representation parts
14608 * RFC 4291 allows you to represent the last two parts of an IPv6 address
14609 * using the standard IPv4 representation
14611 * Example: 0:0:0:0:0:0:13.1.68.3
14612 * 0:0:0:0:0:FFFF:129.144.52.38
14614 * @param string $ip An IPv6 address
14615 * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
14617 private static function split_v6_v4($ip)
14619 if (strpos($ip, '.') !== false)
14621 $pos = strrpos($ip, ':');
14622 $ipv6_part = substr($ip, 0, $pos);
14623 $ipv4_part = substr($ip, $pos + 1);
14624 return array($ipv6_part, $ipv4_part);
14628 return array($ip, '');
14633 * Checks an IPv6 address
14635 * Checks if the given IP is a valid IPv6 address
14637 * @param string $ip An IPv6 address
14638 * @return bool true if $ip is a valid IPv6 address
14640 public static function check_ipv6($ip)
14642 $ip = self::uncompress($ip);
14643 list($ipv6, $ipv4) = self::split_v6_v4($ip);
14644 $ipv6 = explode(':', $ipv6);
14645 $ipv4 = explode('.', $ipv4);
14646 if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
14648 foreach ($ipv6 as $ipv6_part)
14650 // The section can't be empty
14651 if ($ipv6_part === '')
14654 // Nor can it be over four characters
14655 if (strlen($ipv6_part) > 4)
14658 // Remove leading zeros (this is safe because of the above)
14659 $ipv6_part = ltrim($ipv6_part, '0');
14660 if ($ipv6_part === '')
14663 // Check the value is valid
14664 $value = hexdec($ipv6_part);
14665 if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
14668 if (count($ipv4) === 4)
14670 foreach ($ipv4 as $ipv4_part)
14672 $value = (int) $ipv4_part;
14673 if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
14686 * Checks if the given IP is a valid IPv6 address
14688 * @codeCoverageIgnore
14689 * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead
14691 * @param string $ip An IPv6 address
14692 * @return bool true if $ip is a valid IPv6 address
14694 public static function checkIPv6($ip)
14696 return self::check_ipv6($ip);
14703 * @package SimplePie
14704 * @subpackage Parsing
14706 class SimplePie_Parse_Date
14711 * @access protected
14717 * List of days, calendar day name => ordinal day number in the week
14719 * @access protected
14782 'keskiviikko' => 3,
14806 * List of months, calendar month name => calendar month number
14808 * @access protected
14811 var $month = array(
14822 // No long form of May
14951 * List of timezones, abbreviation => offset from UTC
14953 * @access protected
14956 var $timezone = array(
15159 * Cached PCRE for SimplePie_Parse_Date::$day
15161 * @access protected
15167 * Cached PCRE for SimplePie_Parse_Date::$month
15169 * @access protected
15175 * Array of user-added callback methods
15180 var $built_in = array();
15183 * Array of user-added callback methods
15188 var $user = array();
15191 * Create new SimplePie_Parse_Date object, and set self::day_pcre,
15192 * self::month_pcre, and self::built_in
15196 public function __construct()
15198 $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
15199 $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
15202 if (!isset($cache[get_class($this)]))
15204 $all_methods = get_class_methods($this);
15206 foreach ($all_methods as $method)
15208 if (strtolower(substr($method, 0, 5)) === 'date_')
15210 $cache[get_class($this)][] = $method;
15215 foreach ($cache[get_class($this)] as $method)
15217 $this->built_in[] = $method;
15226 public static function get()
15231 $object = new SimplePie_Parse_Date;
15241 * @param string $date Date to parse
15242 * @return int Timestamp corresponding to date string, or false on failure
15244 public function parse($date)
15246 foreach ($this->user as $method)
15248 if (($returned = call_user_func($method, $date)) !== false)
15254 foreach ($this->built_in as $method)
15256 if (($returned = call_user_func(array($this, $method), $date)) !== false)
15266 * Add a callback method to parse a date
15270 * @param callback $callback
15272 public function add_callback($callback)
15274 if (is_callable($callback))
15276 $this->user[] = $callback;
15280 trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
15285 * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
15286 * well as allowing any of upper or lower case "T", horizontal tabs, or
15287 * spaces to be used as the time seperator (including more than one))
15289 * @access protected
15290 * @return int Timestamp
15292 public function date_w3cdtf($date)
15297 $year = '([0-9]{4})';
15298 $month = $day = $hour = $minute = $second = '([0-9]{2})';
15299 $decimal = '([0-9]*)';
15300 $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
15301 $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
15303 if (preg_match($pcre, $date, $match))
15306 Capturing subpatterns:
15313 7: Decimal fraction of a second
15317 11: Timezone minutes
15320 // Fill in empty matches
15321 for ($i = count($match); $i <= 3; $i++)
15326 for ($i = count($match); $i <= 7; $i++)
15331 // Numeric timezone
15332 if (isset($match[9]) && $match[9] !== '')
15334 $timezone = $match[10] * 3600;
15335 $timezone += $match[11] * 60;
15336 if ($match[9] === '-')
15338 $timezone = 0 - $timezone;
15346 // Convert the number of seconds to an integer, taking decimals into account
15347 $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
15349 return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
15358 * Remove RFC822 comments
15360 * @access protected
15361 * @param string $data Data to strip comments from
15362 * @return string Comment stripped string
15364 public function remove_rfc2822_comments($string)
15366 $string = (string) $string;
15368 $length = strlen($string);
15373 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
15375 $output .= substr($string, $position, $pos - $position);
15376 $position = $pos + 1;
15377 if ($string[$pos - 1] !== '\\')
15380 while ($depth && $position < $length)
15382 $position += strcspn($string, '()', $position);
15383 if ($string[$position - 1] === '\\')
15388 elseif (isset($string[$position]))
15390 switch ($string[$position])
15413 $output .= substr($string, $position);
15419 * Parse RFC2822's date format
15421 * @access protected
15422 * @return int Timestamp
15424 public function date_rfc2822($date)
15429 $wsp = '[\x09\x20]';
15430 $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
15431 $optional_fws = $fws . '?';
15432 $day_name = $this->day_pcre;
15433 $month = $this->month_pcre;
15434 $day = '([0-9]{1,2})';
15435 $hour = $minute = $second = '([0-9]{2})';
15436 $year = '([0-9]{2,4})';
15437 $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
15438 $character_zone = '([A-Z]{1,5})';
15439 $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
15440 $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';
15442 if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
15445 Capturing subpatterns:
15455 10: Timezone minutes
15456 11: Alphabetic timezone
15459 // Find the month number
15460 $month = $this->month[strtolower($match[3])];
15462 // Numeric timezone
15463 if ($match[8] !== '')
15465 $timezone = $match[9] * 3600;
15466 $timezone += $match[10] * 60;
15467 if ($match[8] === '-')
15469 $timezone = 0 - $timezone;
15472 // Character timezone
15473 elseif (isset($this->timezone[strtoupper($match[11])]))
15475 $timezone = $this->timezone[strtoupper($match[11])];
15477 // Assume everything else to be -0000
15483 // Deal with 2/3 digit years
15484 if ($match[4] < 50)
15488 elseif ($match[4] < 1000)
15493 // Second is optional, if it is empty set it to zero
15494 if ($match[7] !== '')
15496 $second = $match[7];
15503 return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
15512 * Parse RFC850's date format
15514 * @access protected
15515 * @return int Timestamp
15517 public function date_rfc850($date)
15522 $space = '[\x09\x20]+';
15523 $day_name = $this->day_pcre;
15524 $month = $this->month_pcre;
15525 $day = '([0-9]{1,2})';
15526 $year = $hour = $minute = $second = '([0-9]{2})';
15527 $zone = '([A-Z]{1,5})';
15528 $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
15530 if (preg_match($pcre, $date, $match))
15533 Capturing subpatterns:
15545 $month = $this->month[strtolower($match[3])];
15547 // Character timezone
15548 if (isset($this->timezone[strtoupper($match[8])]))
15550 $timezone = $this->timezone[strtoupper($match[8])];
15552 // Assume everything else to be -0000
15558 // Deal with 2 digit year
15559 if ($match[4] < 50)
15568 return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
15577 * Parse C99's asctime()'s date format
15579 * @access protected
15580 * @return int Timestamp
15582 public function date_asctime($date)
15587 $space = '[\x09\x20]+';
15588 $wday_name = $this->day_pcre;
15589 $mon_name = $this->month_pcre;
15590 $day = '([0-9]{1,2})';
15591 $hour = $sec = $min = '([0-9]{2})';
15592 $year = '([0-9]{4})';
15593 $terminator = '\x0A?\x00?';
15594 $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
15596 if (preg_match($pcre, $date, $match))
15599 Capturing subpatterns:
15609 $month = $this->month[strtolower($match[2])];
15610 return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
15619 * Parse dates using strtotime()
15621 * @access protected
15622 * @return int Timestamp
15624 public function date_strtotime($date)
15626 $strtotime = strtotime($date);
15627 if ($strtotime === -1 || $strtotime === false)
15639 * Parses XML into something sane
15642 * This class can be overloaded with {@see SimplePie::set_parser_class()}
15644 * @package SimplePie
15645 * @subpackage Parsing
15647 class SimplePie_Parser
15652 var $current_column;
15654 var $separator = ' ';
15655 var $namespace = array('');
15656 var $element = array('');
15657 var $xml_base = array('');
15658 var $xml_base_explicit = array(false);
15659 var $xml_lang = array('');
15660 var $data = array();
15661 var $datas = array(array());
15662 var $current_xhtml_construct = -1;
15664 protected $registry;
15666 public function set_registry(SimplePie_Registry $registry)
15668 $this->registry = $registry;
15671 public function parse(&$data, $encoding)
15673 // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
15674 if (strtoupper($encoding) === 'US-ASCII')
15676 $this->encoding = 'UTF-8';
15680 $this->encoding = $encoding;
15684 // UTF-32 Big Endian BOM
15685 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
15687 $data = substr($data, 4);
15689 // UTF-32 Little Endian BOM
15690 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
15692 $data = substr($data, 4);
15694 // UTF-16 Big Endian BOM
15695 elseif (substr($data, 0, 2) === "\xFE\xFF")
15697 $data = substr($data, 2);
15699 // UTF-16 Little Endian BOM
15700 elseif (substr($data, 0, 2) === "\xFF\xFE")
15702 $data = substr($data, 2);
15705 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
15707 $data = substr($data, 3);
15710 if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
15712 $declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
15713 if ($declaration->parse())
15715 $data = substr($data, $pos + 2);
15716 $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
15720 $this->error_string = 'SimplePie bug! Please report this!';
15727 static $xml_is_sane = null;
15728 if ($xml_is_sane === null)
15730 $parser_check = xml_parser_create();
15731 xml_parse_into_struct($parser_check, '<foo>&</foo>', $values);
15732 xml_parser_free($parser_check);
15733 $xml_is_sane = isset($values[0]['value']);
15736 // Create the parser
15739 $xml = xml_parser_create_ns($this->encoding, $this->separator);
15740 xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
15741 xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
15742 xml_set_object($xml, $this);
15743 xml_set_character_data_handler($xml, 'cdata');
15744 xml_set_element_handler($xml, 'tag_open', 'tag_close');
15747 if (!xml_parse($xml, $data, true))
15749 $this->error_code = xml_get_error_code($xml);
15750 $this->error_string = xml_error_string($this->error_code);
15753 $this->current_line = xml_get_current_line_number($xml);
15754 $this->current_column = xml_get_current_column_number($xml);
15755 $this->current_byte = xml_get_current_byte_index($xml);
15756 xml_parser_free($xml);
15761 libxml_clear_errors();
15762 $xml = new XMLReader();
15764 while (@$xml->read())
15766 switch ($xml->nodeType)
15769 case constant('XMLReader::END_ELEMENT'):
15770 if ($xml->namespaceURI !== '')
15772 $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
15776 $tagName = $xml->localName;
15778 $this->tag_close(null, $tagName);
15780 case constant('XMLReader::ELEMENT'):
15781 $empty = $xml->isEmptyElement;
15782 if ($xml->namespaceURI !== '')
15784 $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
15788 $tagName = $xml->localName;
15790 $attributes = array();
15791 while ($xml->moveToNextAttribute())
15793 if ($xml->namespaceURI !== '')
15795 $attrName = $xml->namespaceURI . $this->separator . $xml->localName;
15799 $attrName = $xml->localName;
15801 $attributes[$attrName] = $xml->value;
15803 $this->tag_open(null, $tagName, $attributes);
15806 $this->tag_close(null, $tagName);
15809 case constant('XMLReader::TEXT'):
15811 case constant('XMLReader::CDATA'):
15812 $this->cdata(null, $xml->value);
15816 if ($error = libxml_get_last_error())
15818 $this->error_code = $error->code;
15819 $this->error_string = $error->message;
15820 $this->current_line = $error->line;
15821 $this->current_column = $error->column;
15831 public function get_error_code()
15833 return $this->error_code;
15836 public function get_error_string()
15838 return $this->error_string;
15841 public function get_current_line()
15843 return $this->current_line;
15846 public function get_current_column()
15848 return $this->current_column;
15851 public function get_current_byte()
15853 return $this->current_byte;
15856 public function get_data()
15858 return $this->data;
15861 public function tag_open($parser, $tag, $attributes)
15863 list($this->namespace[], $this->element[]) = $this->split_ns($tag);
15865 $attribs = array();
15866 foreach ($attributes as $name => $value)
15868 list($attrib_namespace, $attribute) = $this->split_ns($name);
15869 $attribs[$attrib_namespace][$attribute] = $value;
15872 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
15874 $base = $this->registry->call('Misc', 'absolutize_url', array($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)));
15875 if ($base !== false)
15877 $this->xml_base[] = $base;
15878 $this->xml_base_explicit[] = true;
15883 $this->xml_base[] = end($this->xml_base);
15884 $this->xml_base_explicit[] = end($this->xml_base_explicit);
15887 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
15889 $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
15893 $this->xml_lang[] = end($this->xml_lang);
15896 if ($this->current_xhtml_construct >= 0)
15898 $this->current_xhtml_construct++;
15899 if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML)
15901 $this->data['data'] .= '<' . end($this->element);
15902 if (isset($attribs['']))
15904 foreach ($attribs[''] as $name => $value)
15906 $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
15909 $this->data['data'] .= '>';
15914 $this->datas[] =& $this->data;
15915 $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
15916 $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));
15917 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')
15918 || (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')
15919 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_20 && in_array(end($this->element), array('title')))
15920 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_090 && in_array(end($this->element), array('title')))
15921 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_10 && in_array(end($this->element), array('title'))))
15923 $this->current_xhtml_construct = 0;
15928 public function cdata($parser, $cdata)
15930 if ($this->current_xhtml_construct >= 0)
15932 $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
15936 $this->data['data'] .= $cdata;
15940 public function tag_close($parser, $tag)
15942 if ($this->current_xhtml_construct >= 0)
15944 $this->current_xhtml_construct--;
15945 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')))
15947 $this->data['data'] .= '</' . end($this->element) . '>';
15950 if ($this->current_xhtml_construct === -1)
15952 $this->data =& $this->datas[count($this->datas) - 1];
15953 array_pop($this->datas);
15956 array_pop($this->element);
15957 array_pop($this->namespace);
15958 array_pop($this->xml_base);
15959 array_pop($this->xml_base_explicit);
15960 array_pop($this->xml_lang);
15963 public function split_ns($string)
15965 static $cache = array();
15966 if (!isset($cache[$string]))
15968 if ($pos = strpos($string, $this->separator))
15970 static $separator_length;
15971 if (!$separator_length)
15973 $separator_length = strlen($this->separator);
15975 $namespace = substr($string, 0, $pos);
15976 $local_name = substr($string, $pos + $separator_length);
15977 if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
15979 $namespace = SIMPLEPIE_NAMESPACE_ITUNES;
15982 // Normalize the Media RSS namespaces
15983 if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG ||
15984 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2 ||
15985 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3 ||
15986 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4 ||
15987 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5 )
15989 $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
15991 $cache[$string] = array($namespace, $local_name);
15995 $cache[$string] = array('', $string);
15998 return $cache[$string];
16003 * Handles `<media:rating>` or `<itunes:explicit>` tags as defined in Media RSS and iTunes RSS respectively
16005 * Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()}
16007 * This class can be overloaded with {@see SimplePie::set_rating_class()}
16009 * @package SimplePie
16012 class SimplePie_Rating
16018 * @see get_scheme()
16031 * Constructor, used to input the data
16033 * For documentation on all the parameters, see the corresponding
16034 * properties and their accessors
16036 public function __construct($scheme = null, $value = null)
16038 $this->scheme = $scheme;
16039 $this->value = $value;
16043 * String-ified version
16047 public function __toString()
16049 // There is no $this->data here
16050 return md5(serialize($this));
16054 * Get the organizational scheme for the rating
16056 * @return string|null
16058 public function get_scheme()
16060 if ($this->scheme !== null)
16062 return $this->scheme;
16071 * Get the value of the rating
16073 * @return string|null
16075 public function get_value()
16077 if ($this->value !== null)
16079 return $this->value;
16089 * Handles creating objects and calling methods
16091 * Access this via {@see SimplePie::get_registry()}
16093 * @package SimplePie
16095 class SimplePie_Registry
16098 * Default class mapping
16100 * Overriding classes *must* subclass these.
16104 protected $default = array(
16105 'Cache' => 'SimplePie_Cache',
16106 'Locator' => 'SimplePie_Locator',
16107 'Parser' => 'SimplePie_Parser',
16108 'File' => 'SimplePie_File',
16109 'Sanitize' => 'SimplePie_Sanitize',
16110 'Item' => 'SimplePie_Item',
16111 'Author' => 'SimplePie_Author',
16112 'Category' => 'SimplePie_Category',
16113 'Enclosure' => 'SimplePie_Enclosure',
16114 'Caption' => 'SimplePie_Caption',
16115 'Copyright' => 'SimplePie_Copyright',
16116 'Credit' => 'SimplePie_Credit',
16117 'Rating' => 'SimplePie_Rating',
16118 'Restriction' => 'SimplePie_Restriction',
16119 'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer',
16120 'Source' => 'SimplePie_Source',
16121 'Misc' => 'SimplePie_Misc',
16122 'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser',
16123 'Parse_Date' => 'SimplePie_Parse_Date',
16132 protected $classes = array();
16140 protected $legacy = array();
16147 public function __construct() { }
16152 * @param string $type See {@see $default} for names
16153 * @param string $class Class name, must subclass the corresponding default
16154 * @param bool $legacy Whether to enable legacy support for this class
16155 * @return bool Successfulness
16157 public function register($type, $class, $legacy = false)
16159 if (!is_subclass_of($class, $this->default[$type]))
16164 $this->classes[$type] = $class;
16168 $this->legacy[] = $class;
16175 * Get the class registered for a type
16177 * Where possible, use {@see create()} or {@see call()} instead
16179 * @param string $type
16180 * @return string|null
16182 public function get_class($type)
16184 if (!empty($this->classes[$type]))
16186 return $this->classes[$type];
16188 if (!empty($this->default[$type]))
16190 return $this->default[$type];
16197 * Create a new instance of a given type
16199 * @param string $type
16200 * @param array $parameters Parameters to pass to the constructor
16201 * @return object Instance of class
16203 public function &create($type, $parameters = array())
16205 $class = $this->get_class($type);
16207 if (in_array($class, $this->legacy))
16212 // Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class
16213 // Specified: file, timeout, useragent, max_checked_feeds
16214 $replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer'));
16215 array_splice($parameters, 3, 1, $replacement);
16220 if (!method_exists($class, '__construct'))
16222 $instance = new $class;
16226 $reflector = new ReflectionClass($class);
16227 $instance = $reflector->newInstanceArgs($parameters);
16230 if (method_exists($instance, 'set_registry'))
16232 $instance->set_registry($this);
16238 * Call a static method for a type
16240 * @param string $type
16241 * @param string $method
16242 * @param array $parameters
16245 public function &call($type, $method, $parameters = array())
16247 $class = $this->get_class($type);
16249 if (in_array($class, $this->legacy))
16254 // For backwards compatibility with old non-static
16255 // Cache::create() methods
16256 if ($method === 'get_handler')
16258 $result = @call_user_func_array(array($class, 'create'), $parameters);
16265 $result = call_user_func_array(array($class, $method), $parameters);
16271 * Handles `<media:restriction>` as defined in Media RSS
16273 * Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()}
16275 * This class can be overloaded with {@see SimplePie::set_restriction_class()}
16277 * @package SimplePie
16280 class SimplePie_Restriction
16283 * Relationship ('allow'/'deny')
16286 * @see get_relationship()
16291 * Type of restriction
16299 * Restricted values
16307 * Constructor, used to input the data
16309 * For documentation on all the parameters, see the corresponding
16310 * properties and their accessors
16312 public function __construct($relationship = null, $type = null, $value = null)
16314 $this->relationship = $relationship;
16315 $this->type = $type;
16316 $this->value = $value;
16320 * String-ified version
16324 public function __toString()
16326 // There is no $this->data here
16327 return md5(serialize($this));
16331 * Get the relationship
16333 * @return string|null Either 'allow' or 'deny'
16335 public function get_relationship()
16337 if ($this->relationship !== null)
16339 return $this->relationship;
16350 * @return string|null
16352 public function get_type()
16354 if ($this->type !== null)
16356 return $this->type;
16365 * Get the list of restricted things
16367 * @return string|null
16369 public function get_value()
16371 if ($this->value !== null)
16373 return $this->value;
16383 * Used for data cleanup and post-processing
16386 * This class can be overloaded with {@see SimplePie::set_sanitize_class()}
16388 * @package SimplePie
16389 * @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
16391 class SimplePie_Sanitize
16397 var $remove_div = true;
16398 var $image_handler = '';
16399 var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
16400 var $encode_instead_of_strip = false;
16401 var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
16402 var $strip_comments = false;
16403 var $output_encoding = 'UTF-8';
16404 var $enable_cache = true;
16405 var $cache_location = './cache';
16406 var $cache_name_function = 'md5';
16408 var $useragent = '';
16409 var $force_fsockopen = false;
16410 var $replace_url_attributes = null;
16412 public function __construct()
16415 $this->set_url_replacements(null);
16418 public function remove_div($enable = true)
16420 $this->remove_div = (bool) $enable;
16423 public function set_image_handler($page = false)
16427 $this->image_handler = (string) $page;
16431 $this->image_handler = false;
16435 public function set_registry(SimplePie_Registry $registry)
16437 $this->registry = $registry;
16440 public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
16442 if (isset($enable_cache))
16444 $this->enable_cache = (bool) $enable_cache;
16447 if ($cache_location)
16449 $this->cache_location = (string) $cache_location;
16452 if ($cache_name_function)
16454 $this->cache_name_function = (string) $cache_name_function;
16458 public function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
16462 $this->timeout = (string) $timeout;
16467 $this->useragent = (string) $useragent;
16470 if ($force_fsockopen)
16472 $this->force_fsockopen = (string) $force_fsockopen;
16476 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'))
16480 if (is_array($tags))
16482 $this->strip_htmltags = $tags;
16486 $this->strip_htmltags = explode(',', $tags);
16491 $this->strip_htmltags = false;
16495 public function encode_instead_of_strip($encode = false)
16497 $this->encode_instead_of_strip = (bool) $encode;
16500 public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
16504 if (is_array($attribs))
16506 $this->strip_attributes = $attribs;
16510 $this->strip_attributes = explode(',', $attribs);
16515 $this->strip_attributes = false;
16519 public function strip_comments($strip = false)
16521 $this->strip_comments = (bool) $strip;
16524 public function set_output_encoding($encoding = 'UTF-8')
16526 $this->output_encoding = (string) $encoding;
16530 * Set element/attribute key/value pairs of HTML attributes
16531 * containing URLs that need to be resolved relative to the feed
16533 * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
16534 * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
16538 * @param array|null $element_attribute Element/attribute key/value pairs, null for default
16540 public function set_url_replacements($element_attribute = null)
16542 if ($element_attribute === null)
16544 $element_attribute = array(
16547 'blockquote' => 'cite',
16549 'form' => 'action',
16559 $this->replace_url_attributes = (array) $element_attribute;
16562 public function sanitize($data, $type, $base = '')
16564 $data = trim($data);
16565 if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
16567 if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
16569 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))
16571 $type |= SIMPLEPIE_CONSTRUCT_HTML;
16575 $type |= SIMPLEPIE_CONSTRUCT_TEXT;
16579 if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
16581 $data = base64_decode($data);
16584 if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
16587 $document = new DOMDocument();
16588 $document->encoding = 'UTF-8';
16589 $data = $this->preprocess($data, $type);
16591 set_error_handler(array('SimplePie_Misc', 'silence_errors'));
16592 $document->loadHTML($data);
16593 restore_error_handler();
16596 if ($this->strip_comments)
16598 $xpath = new DOMXPath($document);
16599 $comments = $xpath->query('//comment()');
16601 foreach ($comments as $comment)
16603 $comment->parentNode->removeChild($comment);
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)
16612 foreach ($this->strip_htmltags as $tag)
16614 $this->strip_tag($tag, $document, $type);
16618 if ($this->strip_attributes)
16620 foreach ($this->strip_attributes as $attrib)
16622 $this->strip_attr($attrib, $document);
16626 // Replace relative URLs
16627 $this->base = $base;
16628 foreach ($this->replace_url_attributes as $element => $attributes)
16630 $this->replace_urls($document, $element, $attributes);
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)
16636 $images = $document->getElementsByTagName('img');
16637 foreach ($images as $img)
16639 if ($img->hasAttribute('src'))
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'));
16644 if ($cache->load())
16646 $img->setAttribute('src', $this->image_handler . $image_url);
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;
16653 if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
16655 if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
16657 $img->setAttribute('src', $this->image_handler . $image_url);
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);
16669 // Remove the DOCTYPE
16670 // Seems to cause segfaulting if we don't do this
16671 if ($document->firstChild instanceof DOMDocumentType)
16673 $document->removeChild($document->firstChild);
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);
16680 // Finally, convert to a HTML string
16681 $data = trim($document->saveHTML());
16683 if ($this->remove_div)
16685 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
16686 $data = preg_replace('/<\/div>$/', '', $data);
16690 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
16694 if ($type & SIMPLEPIE_CONSTRUCT_IRI)
16696 $absolute = $this->registry->call('Misc', 'absolutize_url', array($data, $base));
16697 if ($absolute !== false)
16703 if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
16705 $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
16708 if ($this->output_encoding !== 'UTF-8')
16710 $data = $this->registry->call('Misc', 'change_encoding', array($data, 'UTF-8', $this->output_encoding));
16716 protected function preprocess($html, $type)
16719 if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML)
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';
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';
16733 $ret .= '<html><head>';
16734 $ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />';
16735 $ret .= '</head><body>' . $html . '</body></html>';
16739 public function replace_urls($document, $tag, $attributes)
16741 if (!is_array($attributes))
16743 $attributes = array($attributes);
16746 if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
16748 $elements = $document->getElementsByTagName($tag);
16749 foreach ($elements as $element)
16751 foreach ($attributes as $attribute)
16753 if ($element->hasAttribute($attribute))
16755 $value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base));
16756 if ($value !== false)
16758 $element->setAttribute($attribute, $value);
16766 public function do_strip_htmltags($match)
16768 if ($this->encode_instead_of_strip)
16770 if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
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]>";
16778 return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
16781 elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
16791 protected function strip_tag($tag, $document, $type)
16793 $xpath = new DOMXPath($document);
16794 $elements = $xpath->query('body//' . $tag);
16795 if ($this->encode_instead_of_strip)
16797 foreach ($elements as $element)
16799 $fragment = $document->createDocumentFragment();
16801 // For elements which aren't script or style, include the tag itself
16802 if (!in_array($tag, array('script', 'style')))
16804 $text = '<' . $tag;
16805 if ($element->hasAttributes())
16808 foreach ($element->attributes as $name => $attr)
16810 $value = $attr->value;
16812 // In XHTML, empty values should never exist, so we repeat the value
16813 if (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_XHTML))
16817 // For HTML, empty is fine
16818 elseif (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_HTML))
16824 // Standard attribute text
16825 $attrs[] = $name . '="' . $attr->value . '"';
16827 $text .= ' ' . implode(' ', $attrs);
16830 $fragment->appendChild(new DOMText($text));
16833 $number = $element->childNodes->length;
16834 for ($i = $number; $i > 0; $i--)
16836 $child = $element->childNodes->item(0);
16837 $fragment->appendChild($child);
16840 if (!in_array($tag, array('script', 'style')))
16842 $fragment->appendChild(new DOMText('</' . $tag . '>'));
16845 $element->parentNode->replaceChild($fragment, $element);
16850 elseif (in_array($tag, array('script', 'style')))
16852 foreach ($elements as $element)
16854 $element->parentNode->removeChild($element);
16861 foreach ($elements as $element)
16863 $fragment = $document->createDocumentFragment();
16864 $number = $element->childNodes->length;
16865 for ($i = $number; $i > 0; $i--)
16867 $child = $element->childNodes->item(0);
16868 $fragment->appendChild($child);
16871 $element->parentNode->replaceChild($fragment, $element);
16876 protected function strip_attr($attrib, $document)
16878 $xpath = new DOMXPath($document);
16879 $elements = $xpath->query('//*[@' . $attrib . ']');
16881 foreach ($elements as $element)
16883 $element->removeAttribute($attrib);
16889 * Handles `<atom:source>`
16891 * Used by {@see SimplePie_Item::get_source()}
16893 * This class can be overloaded with {@see SimplePie::set_source_class()}
16895 * @package SimplePie
16898 class SimplePie_Source
16901 var $data = array();
16902 protected $registry;
16904 public function __construct($item, $data)
16906 $this->item = $item;
16907 $this->data = $data;
16910 public function set_registry(SimplePie_Registry $registry)
16912 $this->registry = $registry;
16915 public function __toString()
16917 return md5(serialize($this->data));
16920 public function get_source_tags($namespace, $tag)
16922 if (isset($this->data['child'][$namespace][$tag]))
16924 return $this->data['child'][$namespace][$tag];
16932 public function get_base($element = array())
16934 return $this->item->get_base($element);
16937 public function sanitize($data, $type, $base = '')
16939 return $this->item->sanitize($data, $type, $base);
16942 public function get_item()
16944 return $this->item;
16947 public function get_title()
16949 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
16951 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
16953 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
16955 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
16957 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
16959 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
16961 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
16963 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
16965 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
16967 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
16969 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
16971 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
16973 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
16975 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
16983 public function get_category($key = 0)
16985 $categories = $this->get_categories();
16986 if (isset($categories[$key]))
16988 return $categories[$key];
16996 public function get_categories()
16998 $categories = array();
17000 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
17005 if (isset($category['attribs']['']['term']))
17007 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
17009 if (isset($category['attribs']['']['scheme']))
17011 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
17013 if (isset($category['attribs']['']['label']))
17015 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
17017 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
17019 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
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']))
17026 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
17032 $categories[] = $this->registry->create('Category', array($term, $scheme, null));
17034 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
17036 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17038 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
17040 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17043 if (!empty($categories))
17045 return array_unique($categories);
17053 public function get_author($key = 0)
17055 $authors = $this->get_authors();
17056 if (isset($authors[$key]))
17058 return $authors[$key];
17066 public function get_authors()
17068 $authors = array();
17069 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
17074 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
17076 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17078 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
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]));
17082 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
17084 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17086 if ($name !== null || $email !== null || $uri !== null)
17088 $authors[] = $this->registry->create('Author', array($name, $uri, $email));
17091 if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
17096 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
17098 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17100 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
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]));
17104 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
17106 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17108 if ($name !== null || $email !== null || $url !== null)
17110 $authors[] = $this->registry->create('Author', array($name, $url, $email));
17113 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
17115 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17117 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
17119 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17121 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
17123 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17126 if (!empty($authors))
17128 return array_unique($authors);
17136 public function get_contributor($key = 0)
17138 $contributors = $this->get_contributors();
17139 if (isset($contributors[$key]))
17141 return $contributors[$key];
17149 public function get_contributors()
17151 $contributors = array();
17152 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
17157 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
17159 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17161 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
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]));
17165 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
17167 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17169 if ($name !== null || $email !== null || $uri !== null)
17171 $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
17174 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
17179 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
17181 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17183 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
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]));
17187 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
17189 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17191 if ($name !== null || $email !== null || $url !== null)
17193 $contributors[] = $this->registry->create('Author', array($name, $url, $email));
17197 if (!empty($contributors))
17199 return array_unique($contributors);
17207 public function get_link($key = 0, $rel = 'alternate')
17209 $links = $this->get_links($rel);
17210 if (isset($links[$key]))
17212 return $links[$key];
17221 * Added for parity between the parent-level and the item/entry-level.
17223 public function get_permalink()
17225 return $this->get_link(0);
17228 public function get_links($rel = 'alternate')
17230 if (!isset($this->data['links']))
17232 $this->data['links'] = array();
17233 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
17235 foreach ($links as $link)
17237 if (isset($link['attribs']['']['href']))
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));
17244 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
17246 foreach ($links as $link)
17248 if (isset($link['attribs']['']['href']))
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));
17256 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
17258 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
17260 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
17262 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
17264 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
17266 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
17269 $keys = array_keys($this->data['links']);
17270 foreach ($keys as $key)
17272 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
17274 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
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];
17281 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
17284 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
17286 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
17288 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
17292 if (isset($this->data['links'][$rel]))
17294 return $this->data['links'][$rel];
17302 public function get_description()
17304 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
17306 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17308 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
17310 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17312 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
17314 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
17316 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
17318 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
17320 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
17322 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
17324 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
17326 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17328 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
17330 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17332 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
17334 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
17336 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
17338 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
17346 public function get_copyright()
17348 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
17350 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17352 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
17354 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17356 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
17358 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17360 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
17362 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17364 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
17366 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17374 public function get_language()
17376 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
17378 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17380 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
17382 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17384 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
17386 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17388 elseif (isset($this->data['xml_lang']))
17390 return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
17398 public function get_latitude()
17400 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
17402 return (float) $return[0]['data'];
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))
17406 return (float) $match[1];
17414 public function get_longitude()
17416 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
17418 return (float) $return[0]['data'];
17420 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
17422 return (float) $return[0]['data'];
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))
17426 return (float) $match[2];
17434 public function get_image_url()
17436 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
17438 return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
17440 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
17442 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
17444 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
17446 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
17456 * Parses the XML Declaration
17458 * @package SimplePie
17459 * @subpackage Parsing
17461 class SimplePie_XML_Declaration_Parser
17469 var $version = '1.0';
17477 var $encoding = 'UTF-8';
17485 var $standalone = false;
17488 * Current state of the state machine
17493 var $state = 'before_version_name';
17504 * Input data length (to avoid calling strlen() everytime this is needed)
17509 var $data_length = 0;
17512 * Current position of the pointer
17520 * Create an instance of the class with the input data
17523 * @param string $data Input data
17525 public function __construct($data)
17527 $this->data = $data;
17528 $this->data_length = strlen($this->data);
17532 * Parse the input data
17535 * @return bool true on success, false on failure
17537 public function parse()
17539 while ($this->state && $this->state !== 'emit' && $this->has_data())
17541 $state = $this->state;
17545 if ($this->state === 'emit')
17551 $this->version = '';
17552 $this->encoding = '';
17553 $this->standalone = '';
17559 * Check whether there is data beyond the pointer
17562 * @return bool true if there is further data, false if not
17564 public function has_data()
17566 return (bool) ($this->position < $this->data_length);
17570 * Advance past any whitespace
17572 * @return int Number of whitespace characters passed
17574 public function skip_whitespace()
17576 $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
17577 $this->position += $whitespace;
17578 return $whitespace;
17584 public function get_value()
17586 $quote = substr($this->data, $this->position, 1);
17587 if ($quote === '"' || $quote === "'")
17590 $len = strcspn($this->data, $quote, $this->position);
17591 if ($this->has_data())
17593 $value = substr($this->data, $this->position, $len);
17594 $this->position += $len + 1;
17601 public function before_version_name()
17603 if ($this->skip_whitespace())
17605 $this->state = 'version_name';
17609 $this->state = false;
17613 public function version_name()
17615 if (substr($this->data, $this->position, 7) === 'version')
17617 $this->position += 7;
17618 $this->skip_whitespace();
17619 $this->state = 'version_equals';
17623 $this->state = false;
17627 public function version_equals()
17629 if (substr($this->data, $this->position, 1) === '=')
17632 $this->skip_whitespace();
17633 $this->state = 'version_value';
17637 $this->state = false;
17641 public function version_value()
17643 if ($this->version = $this->get_value())
17645 $this->skip_whitespace();
17646 if ($this->has_data())
17648 $this->state = 'encoding_name';
17652 $this->state = 'emit';
17657 $this->state = false;
17661 public function encoding_name()
17663 if (substr($this->data, $this->position, 8) === 'encoding')
17665 $this->position += 8;
17666 $this->skip_whitespace();
17667 $this->state = 'encoding_equals';
17671 $this->state = 'standalone_name';
17675 public function encoding_equals()
17677 if (substr($this->data, $this->position, 1) === '=')
17680 $this->skip_whitespace();
17681 $this->state = 'encoding_value';
17685 $this->state = false;
17689 public function encoding_value()
17691 if ($this->encoding = $this->get_value())
17693 $this->skip_whitespace();
17694 if ($this->has_data())
17696 $this->state = 'standalone_name';
17700 $this->state = 'emit';
17705 $this->state = false;
17709 public function standalone_name()
17711 if (substr($this->data, $this->position, 10) === 'standalone')
17713 $this->position += 10;
17714 $this->skip_whitespace();
17715 $this->state = 'standalone_equals';
17719 $this->state = false;
17723 public function standalone_equals()
17725 if (substr($this->data, $this->position, 1) === '=')
17728 $this->skip_whitespace();
17729 $this->state = 'standalone_value';
17733 $this->state = false;
17737 public function standalone_value()
17739 if ($standalone = $this->get_value())
17741 switch ($standalone)
17744 $this->standalone = true;
17748 $this->standalone = false;
17752 $this->state = false;
17756 $this->skip_whitespace();
17757 if ($this->has_data())
17759 $this->state = false;
17763 $this->state = 'emit';
17768 $this->state = false;