Added diff navigation
[dokuwiki.git] / inc / SimplePie.php
blob10d8141bd9722b2fc2f5bbe780fc6ae319042f76
1 <?php
2 /**
3 * SimplePie
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
8 * Copyright (c) 2004-2011, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
35 * @package SimplePie
36 * @version 1.2.1
37 * @copyright 2004-2011 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @link http://simplepie.org/support/ Please submit all bug reports and feature requests to the SimplePie forums
43 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
44 * @todo phpDoc comments
47 /**
48 * SimplePie Name
50 define('SIMPLEPIE_NAME', 'SimplePie');
52 /**
53 * SimplePie Version
55 define('SIMPLEPIE_VERSION', '1.2.1-dev');
57 /**
58 * SimplePie Build
60 define('SIMPLEPIE_BUILD', '20111015034325');
62 /**
63 * SimplePie Website URL
65 define('SIMPLEPIE_URL', 'http://simplepie.org');
67 /**
68 * SimplePie Useragent
69 * @see SimplePie::set_useragent()
71 define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
73 /**
74 * SimplePie Linkback
76 define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
78 /**
79 * No Autodiscovery
80 * @see SimplePie::set_autodiscovery_level()
82 define('SIMPLEPIE_LOCATOR_NONE', 0);
84 /**
85 * Feed Link Element Autodiscovery
86 * @see SimplePie::set_autodiscovery_level()
88 define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
90 /**
91 * Local Feed Extension Autodiscovery
92 * @see SimplePie::set_autodiscovery_level()
94 define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
96 /**
97 * Local Feed Body Autodiscovery
98 * @see SimplePie::set_autodiscovery_level()
100 define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
103 * Remote Feed Extension Autodiscovery
104 * @see SimplePie::set_autodiscovery_level()
106 define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
109 * Remote Feed Body Autodiscovery
110 * @see SimplePie::set_autodiscovery_level()
112 define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
115 * All Feed Autodiscovery
116 * @see SimplePie::set_autodiscovery_level()
118 define('SIMPLEPIE_LOCATOR_ALL', 31);
121 * No known feed type
123 define('SIMPLEPIE_TYPE_NONE', 0);
126 * RSS 0.90
128 define('SIMPLEPIE_TYPE_RSS_090', 1);
131 * RSS 0.91 (Netscape)
133 define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
136 * RSS 0.91 (Userland)
138 define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
141 * RSS 0.91 (both Netscape and Userland)
143 define('SIMPLEPIE_TYPE_RSS_091', 6);
146 * RSS 0.92
148 define('SIMPLEPIE_TYPE_RSS_092', 8);
151 * RSS 0.93
153 define('SIMPLEPIE_TYPE_RSS_093', 16);
156 * RSS 0.94
158 define('SIMPLEPIE_TYPE_RSS_094', 32);
161 * RSS 1.0
163 define('SIMPLEPIE_TYPE_RSS_10', 64);
166 * RSS 2.0
168 define('SIMPLEPIE_TYPE_RSS_20', 128);
171 * RDF-based RSS
173 define('SIMPLEPIE_TYPE_RSS_RDF', 65);
176 * Non-RDF-based RSS (truly intended as syndication format)
178 define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
181 * All RSS
183 define('SIMPLEPIE_TYPE_RSS_ALL', 255);
186 * Atom 0.3
188 define('SIMPLEPIE_TYPE_ATOM_03', 256);
191 * Atom 1.0
193 define('SIMPLEPIE_TYPE_ATOM_10', 512);
196 * All Atom
198 define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
201 * All feed types
203 define('SIMPLEPIE_TYPE_ALL', 1023);
206 * No construct
208 define('SIMPLEPIE_CONSTRUCT_NONE', 0);
211 * Text construct
213 define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
216 * HTML construct
218 define('SIMPLEPIE_CONSTRUCT_HTML', 2);
221 * XHTML construct
223 define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
226 * base64-encoded construct
228 define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
231 * IRI construct
233 define('SIMPLEPIE_CONSTRUCT_IRI', 16);
236 * A construct that might be HTML
238 define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
241 * All constructs
243 define('SIMPLEPIE_CONSTRUCT_ALL', 63);
246 * Don't change case
248 define('SIMPLEPIE_SAME_CASE', 1);
251 * Change to lowercase
253 define('SIMPLEPIE_LOWERCASE', 2);
256 * Change to uppercase
258 define('SIMPLEPIE_UPPERCASE', 4);
261 * PCRE for HTML attributes
263 define('SIMPLEPIE_PCRE_HTML_ATTRIBUTE', '((?:[\x09\x0A\x0B\x0C\x0D\x20]+[^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?)*)[\x09\x0A\x0B\x0C\x0D\x20]*');
266 * PCRE for XML attributes
268 define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
271 * XML Namespace
273 define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
276 * Atom 1.0 Namespace
278 define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
281 * Atom 0.3 Namespace
283 define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
286 * RDF Namespace
288 define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
291 * RSS 0.90 Namespace
293 define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
296 * RSS 1.0 Namespace
298 define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
301 * RSS 1.0 Content Module Namespace
303 define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
306 * RSS 2.0 Namespace
307 * (Stupid, I know, but I'm certain it will confuse people less with support.)
309 define('SIMPLEPIE_NAMESPACE_RSS_20', '');
312 * DC 1.0 Namespace
314 define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
317 * DC 1.1 Namespace
319 define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
322 * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
324 define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
327 * GeoRSS Namespace
329 define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
332 * Media RSS Namespace
334 define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
337 * Wrong Media RSS Namespace
339 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
342 * iTunes RSS Namespace
344 define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
347 * XHTML Namespace
349 define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
352 * IANA Link Relations Registry
354 define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
357 * Whether we're running on PHP5
359 define('SIMPLEPIE_PHP5', version_compare(PHP_VERSION, '5.0.0', '>='));
362 * No file source
364 define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
367 * Remote file source
369 define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
372 * Local file source
374 define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
377 * fsockopen() file source
379 define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
382 * cURL file source
384 define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
387 * file_get_contents() file source
389 define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
392 * SimplePie
394 * @package SimplePie
396 class SimplePie
399 * @var array Raw data
400 * @access private
402 var $data = array();
405 * @var mixed Error string
406 * @access private
408 var $error;
411 * @var object Instance of SimplePie_Sanitize (or other class)
412 * @see SimplePie::set_sanitize_class()
413 * @access private
415 var $sanitize;
418 * @var string SimplePie Useragent
419 * @see SimplePie::set_useragent()
420 * @access private
422 var $useragent = SIMPLEPIE_USERAGENT;
425 * @var string Feed URL
426 * @see SimplePie::set_feed_url()
427 * @access private
429 var $feed_url;
432 * @var object Instance of SimplePie_File to use as a feed
433 * @see SimplePie::set_file()
434 * @access private
436 var $file;
439 * @var string Raw feed data
440 * @see SimplePie::set_raw_data()
441 * @access private
443 var $raw_data;
446 * @var int Timeout for fetching remote files
447 * @see SimplePie::set_timeout()
448 * @access private
450 var $timeout = 10;
453 * @var bool Forces fsockopen() to be used for remote files instead
454 * of cURL, even if a new enough version is installed
455 * @see SimplePie::force_fsockopen()
456 * @access private
458 var $force_fsockopen = false;
461 * @var bool Force the given data/URL to be treated as a feed no matter what
462 * it appears like
463 * @see SimplePie::force_feed()
464 * @access private
466 var $force_feed = false;
469 * @var bool Enable/Disable XML dump
470 * @see SimplePie::enable_xml_dump()
471 * @access private
473 var $xml_dump = false;
476 * @var bool Enable/Disable Caching
477 * @see SimplePie::enable_cache()
478 * @access private
480 var $cache = true;
483 * @var int Cache duration (in seconds)
484 * @see SimplePie::set_cache_duration()
485 * @access private
487 var $cache_duration = 3600;
490 * @var int Auto-discovery cache duration (in seconds)
491 * @see SimplePie::set_autodiscovery_cache_duration()
492 * @access private
494 var $autodiscovery_cache_duration = 604800; // 7 Days.
497 * @var string Cache location (relative to executing script)
498 * @see SimplePie::set_cache_location()
499 * @access private
501 var $cache_location = './cache';
504 * @var string Function that creates the cache filename
505 * @see SimplePie::set_cache_name_function()
506 * @access private
508 var $cache_name_function = 'md5';
511 * @var bool Reorder feed by date descending
512 * @see SimplePie::enable_order_by_date()
513 * @access private
515 var $order_by_date = true;
518 * @var mixed Force input encoding to be set to the follow value
519 * (false, or anything type-cast to false, disables this feature)
520 * @see SimplePie::set_input_encoding()
521 * @access private
523 var $input_encoding = false;
526 * @var int Feed Autodiscovery Level
527 * @see SimplePie::set_autodiscovery_level()
528 * @access private
530 var $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
533 * @var string Class used for caching feeds
534 * @see SimplePie::set_cache_class()
535 * @access private
537 var $cache_class = 'SimplePie_Cache';
540 * @var string Class used for locating feeds
541 * @see SimplePie::set_locator_class()
542 * @access private
544 var $locator_class = 'SimplePie_Locator';
547 * @var string Class used for parsing feeds
548 * @see SimplePie::set_parser_class()
549 * @access private
551 var $parser_class = 'SimplePie_Parser';
554 * @var string Class used for fetching feeds
555 * @see SimplePie::set_file_class()
556 * @access private
558 var $file_class = 'SimplePie_File';
561 * @var string Class used for items
562 * @see SimplePie::set_item_class()
563 * @access private
565 var $item_class = 'SimplePie_Item';
568 * @var string Class used for authors
569 * @see SimplePie::set_author_class()
570 * @access private
572 var $author_class = 'SimplePie_Author';
575 * @var string Class used for categories
576 * @see SimplePie::set_category_class()
577 * @access private
579 var $category_class = 'SimplePie_Category';
582 * @var string Class used for enclosures
583 * @see SimplePie::set_enclosures_class()
584 * @access private
586 var $enclosure_class = 'SimplePie_Enclosure';
589 * @var string Class used for Media RSS <media:text> captions
590 * @see SimplePie::set_caption_class()
591 * @access private
593 var $caption_class = 'SimplePie_Caption';
596 * @var string Class used for Media RSS <media:copyright>
597 * @see SimplePie::set_copyright_class()
598 * @access private
600 var $copyright_class = 'SimplePie_Copyright';
603 * @var string Class used for Media RSS <media:credit>
604 * @see SimplePie::set_credit_class()
605 * @access private
607 var $credit_class = 'SimplePie_Credit';
610 * @var string Class used for Media RSS <media:rating>
611 * @see SimplePie::set_rating_class()
612 * @access private
614 var $rating_class = 'SimplePie_Rating';
617 * @var string Class used for Media RSS <media:restriction>
618 * @see SimplePie::set_restriction_class()
619 * @access private
621 var $restriction_class = 'SimplePie_Restriction';
624 * @var string Class used for content-type sniffing
625 * @see SimplePie::set_content_type_sniffer_class()
626 * @access private
628 var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer';
631 * @var string Class used for item sources.
632 * @see SimplePie::set_source_class()
633 * @access private
635 var $source_class = 'SimplePie_Source';
638 * @var mixed Set javascript query string parameter (false, or
639 * anything type-cast to false, disables this feature)
640 * @see SimplePie::set_javascript()
641 * @access private
643 var $javascript = 'js';
646 * @var int Maximum number of feeds to check with autodiscovery
647 * @see SimplePie::set_max_checked_feeds()
648 * @access private
650 var $max_checked_feeds = 10;
653 * @var array All the feeds found during the autodiscovery process
654 * @see SimplePie::get_all_discovered_feeds()
655 * @access private
657 var $all_discovered_feeds = array();
660 * @var string Web-accessible path to the handler_favicon.php file.
661 * @see SimplePie::set_favicon_handler()
662 * @access private
664 var $favicon_handler = '';
667 * @var string Web-accessible path to the handler_image.php file.
668 * @see SimplePie::set_image_handler()
669 * @access private
671 var $image_handler = '';
674 * @var array Stores the URLs when multiple feeds are being initialized.
675 * @see SimplePie::set_feed_url()
676 * @access private
678 var $multifeed_url = array();
681 * @var array Stores SimplePie objects when multiple feeds initialized.
682 * @access private
684 var $multifeed_objects = array();
687 * @var array Stores the get_object_vars() array for use with multifeeds.
688 * @see SimplePie::set_feed_url()
689 * @access private
691 var $config_settings = null;
694 * @var integer Stores the number of items to return per-feed with multifeeds.
695 * @see SimplePie::set_item_limit()
696 * @access private
698 var $item_limit = 0;
701 * @var array Stores the default attributes to be stripped by strip_attributes().
702 * @see SimplePie::strip_attributes()
703 * @access private
705 var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
708 * @var array Stores the default tags to be stripped by strip_htmltags().
709 * @see SimplePie::strip_htmltags()
710 * @access private
712 var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
715 * The SimplePie class contains feed level data and options
717 * There are two ways that you can create a new SimplePie object. The first
718 * is by passing a feed URL as a parameter to the SimplePie constructor
719 * (as well as optionally setting the cache location and cache expiry). This
720 * will initialise the whole feed with all of the default settings, and you
721 * can begin accessing methods and properties immediately.
723 * The second way is to create the SimplePie object with no parameters
724 * at all. This will enable you to set configuration options. After setting
725 * them, you must initialise the feed using $feed->init(). At that point the
726 * object's methods and properties will be available to you. This format is
727 * what is used throughout this documentation.
729 * @access public
730 * @since 1.0 Preview Release
731 * @param string $feed_url This is the URL you want to parse.
732 * @param string $cache_location This is where you want the cache to be stored.
733 * @param int $cache_duration This is the number of seconds that you want to store the cache file for.
735 function SimplePie($feed_url = null, $cache_location = null, $cache_duration = null)
737 // Other objects, instances created here so we can set options on them
738 $this->sanitize = new SimplePie_Sanitize;
740 // Set options if they're passed to the constructor
741 if ($cache_location !== null)
743 $this->set_cache_location($cache_location);
746 if ($cache_duration !== null)
748 $this->set_cache_duration($cache_duration);
751 // Only init the script if we're passed a feed URL
752 if ($feed_url !== null)
754 $this->set_feed_url($feed_url);
755 $this->init();
760 * Used for converting object to a string
762 function __toString()
764 return md5(serialize($this->data));
768 * Remove items that link back to this before destroying this object
770 function __destruct()
772 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
774 if (!empty($this->data['items']))
776 foreach ($this->data['items'] as $item)
778 $item->__destruct();
780 unset($item, $this->data['items']);
782 if (!empty($this->data['ordered_items']))
784 foreach ($this->data['ordered_items'] as $item)
786 $item->__destruct();
788 unset($item, $this->data['ordered_items']);
794 * Force the given data/URL to be treated as a feed no matter what it
795 * appears like
797 * @access public
798 * @since 1.1
799 * @param bool $enable Force the given data/URL to be treated as a feed
801 function force_feed($enable = false)
803 $this->force_feed = (bool) $enable;
807 * This is the URL of the feed you want to parse.
809 * This allows you to enter the URL of the feed you want to parse, or the
810 * website you want to try to use auto-discovery on. This takes priority
811 * over any set raw data.
813 * You can set multiple feeds to mash together by passing an array instead
814 * of a string for the $url. Remember that with each additional feed comes
815 * additional processing and resources.
817 * @access public
818 * @since 1.0 Preview Release
819 * @param mixed $url This is the URL (or array of URLs) that you want to parse.
820 * @see SimplePie::set_raw_data()
822 function set_feed_url($url)
824 if (is_array($url))
826 $this->multifeed_url = array();
827 foreach ($url as $value)
829 $this->multifeed_url[] = SimplePie_Misc::fix_protocol($value, 1);
832 else
834 $this->feed_url = SimplePie_Misc::fix_protocol($url, 1);
839 * Provides an instance of SimplePie_File to use as a feed
841 * @access public
842 * @param object &$file Instance of SimplePie_File (or subclass)
843 * @return bool True on success, false on failure
845 function set_file(&$file)
847 if (is_a($file, 'SimplePie_File'))
849 $this->feed_url = $file->url;
850 $this->file =& $file;
851 return true;
853 return false;
857 * Allows you to use a string of RSS/Atom data instead of a remote feed.
859 * If you have a feed available as a string in PHP, you can tell SimplePie
860 * to parse that data string instead of a remote feed. Any set feed URL
861 * takes precedence.
863 * @access public
864 * @since 1.0 Beta 3
865 * @param string $data RSS or Atom data as a string.
866 * @see SimplePie::set_feed_url()
868 function set_raw_data($data)
870 $this->raw_data = $data;
874 * Allows you to override the default timeout for fetching remote feeds.
876 * This allows you to change the maximum time the feed's server to respond
877 * and send the feed back.
879 * @access public
880 * @since 1.0 Beta 3
881 * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
883 function set_timeout($timeout = 10)
885 $this->timeout = (int) $timeout;
889 * Forces SimplePie to use fsockopen() instead of the preferred cURL
890 * functions.
892 * @access public
893 * @since 1.0 Beta 3
894 * @param bool $enable Force fsockopen() to be used
896 function force_fsockopen($enable = false)
898 $this->force_fsockopen = (bool) $enable;
902 * Outputs the raw XML content of the feed, after it has gone through
903 * SimplePie's filters.
905 * Used only for debugging, this function will output the XML content as
906 * text/xml. When SimplePie reads in a feed, it does a bit of cleaning up
907 * before trying to parse it. Many parts of the feed are re-written in
908 * memory, and in the end, you have a parsable feed. XML dump shows you the
909 * actual XML that SimplePie tries to parse, which may or may not be very
910 * different from the original feed.
912 * @access public
913 * @since 1.0 Preview Release
914 * @param bool $enable Enable XML dump
916 function enable_xml_dump($enable = false)
918 $this->xml_dump = (bool) $enable;
922 * Enables/disables caching in SimplePie.
924 * This option allows you to disable caching all-together in SimplePie.
925 * However, disabling the cache can lead to longer load times.
927 * @access public
928 * @since 1.0 Preview Release
929 * @param bool $enable Enable caching
931 function enable_cache($enable = true)
933 $this->cache = (bool) $enable;
937 * Set the length of time (in seconds) that the contents of a feed
938 * will be cached.
940 * @access public
941 * @param int $seconds The feed content cache duration.
943 function set_cache_duration($seconds = 3600)
945 $this->cache_duration = (int) $seconds;
949 * Set the length of time (in seconds) that the autodiscovered feed
950 * URL will be cached.
952 * @access public
953 * @param int $seconds The autodiscovered feed URL cache duration.
955 function set_autodiscovery_cache_duration($seconds = 604800)
957 $this->autodiscovery_cache_duration = (int) $seconds;
961 * Set the file system location where the cached files should be stored.
963 * @access public
964 * @param string $location The file system location.
966 function set_cache_location($location = './cache')
968 $this->cache_location = (string) $location;
972 * Determines whether feed items should be sorted into reverse chronological order.
974 * @access public
975 * @param bool $enable Sort as reverse chronological order.
977 function enable_order_by_date($enable = true)
979 $this->order_by_date = (bool) $enable;
983 * Allows you to override the character encoding reported by the feed.
985 * @access public
986 * @param string $encoding Character encoding.
988 function set_input_encoding($encoding = false)
990 if ($encoding)
992 $this->input_encoding = (string) $encoding;
994 else
996 $this->input_encoding = false;
1001 * Set how much feed autodiscovery to do
1003 * @access public
1004 * @see SIMPLEPIE_LOCATOR_NONE
1005 * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
1006 * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
1007 * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
1008 * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
1009 * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
1010 * @see SIMPLEPIE_LOCATOR_ALL
1011 * @param int $level Feed Autodiscovery Level (level can be a
1012 * combination of the above constants, see bitwise OR operator)
1014 function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
1016 $this->autodiscovery = (int) $level;
1020 * Allows you to change which class SimplePie uses for caching.
1021 * Useful when you are overloading or extending SimplePie's default classes.
1023 * @access public
1024 * @param string $class Name of custom class.
1025 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1026 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1028 function set_cache_class($class = 'SimplePie_Cache')
1030 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Cache'))
1032 $this->cache_class = $class;
1033 return true;
1035 return false;
1039 * Allows you to change which class SimplePie uses for auto-discovery.
1040 * Useful when you are overloading or extending SimplePie's default classes.
1042 * @access public
1043 * @param string $class Name of custom class.
1044 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1045 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1047 function set_locator_class($class = 'SimplePie_Locator')
1049 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Locator'))
1051 $this->locator_class = $class;
1052 return true;
1054 return false;
1058 * Allows you to change which class SimplePie uses for XML parsing.
1059 * Useful when you are overloading or extending SimplePie's default classes.
1061 * @access public
1062 * @param string $class Name of custom class.
1063 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1064 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1066 function set_parser_class($class = 'SimplePie_Parser')
1068 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Parser'))
1070 $this->parser_class = $class;
1071 return true;
1073 return false;
1077 * Allows you to change which class SimplePie uses for remote file fetching.
1078 * Useful when you are overloading or extending SimplePie's default classes.
1080 * @access public
1081 * @param string $class Name of custom class.
1082 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1083 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1085 function set_file_class($class = 'SimplePie_File')
1087 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_File'))
1089 $this->file_class = $class;
1090 return true;
1092 return false;
1096 * Allows you to change which class SimplePie uses for data sanitization.
1097 * Useful when you are overloading or extending SimplePie's default classes.
1099 * @access public
1100 * @param string $class Name of custom class.
1101 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1102 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1104 function set_sanitize_class($class = 'SimplePie_Sanitize')
1106 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Sanitize'))
1108 $this->sanitize = new $class;
1109 return true;
1111 return false;
1115 * Allows you to change which class SimplePie uses for handling feed items.
1116 * Useful when you are overloading or extending SimplePie's default classes.
1118 * @access public
1119 * @param string $class Name of custom class.
1120 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1121 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1123 function set_item_class($class = 'SimplePie_Item')
1125 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Item'))
1127 $this->item_class = $class;
1128 return true;
1130 return false;
1134 * Allows you to change which class SimplePie uses for handling author data.
1135 * Useful when you are overloading or extending SimplePie's default classes.
1137 * @access public
1138 * @param string $class Name of custom class.
1139 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1140 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1142 function set_author_class($class = 'SimplePie_Author')
1144 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Author'))
1146 $this->author_class = $class;
1147 return true;
1149 return false;
1153 * Allows you to change which class SimplePie uses for handling category data.
1154 * Useful when you are overloading or extending SimplePie's default classes.
1156 * @access public
1157 * @param string $class Name of custom class.
1158 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1159 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1161 function set_category_class($class = 'SimplePie_Category')
1163 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Category'))
1165 $this->category_class = $class;
1166 return true;
1168 return false;
1172 * Allows you to change which class SimplePie uses for feed enclosures.
1173 * Useful when you are overloading or extending SimplePie's default classes.
1175 * @access public
1176 * @param string $class Name of custom class.
1177 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1178 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1180 function set_enclosure_class($class = 'SimplePie_Enclosure')
1182 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Enclosure'))
1184 $this->enclosure_class = $class;
1185 return true;
1187 return false;
1191 * Allows you to change which class SimplePie uses for <media:text> captions
1192 * Useful when you are overloading or extending SimplePie's default classes.
1194 * @access public
1195 * @param string $class Name of custom class.
1196 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1197 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1199 function set_caption_class($class = 'SimplePie_Caption')
1201 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Caption'))
1203 $this->caption_class = $class;
1204 return true;
1206 return false;
1210 * Allows you to change which class SimplePie uses for <media:copyright>
1211 * Useful when you are overloading or extending SimplePie's default classes.
1213 * @access public
1214 * @param string $class Name of custom class.
1215 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1216 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1218 function set_copyright_class($class = 'SimplePie_Copyright')
1220 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Copyright'))
1222 $this->copyright_class = $class;
1223 return true;
1225 return false;
1229 * Allows you to change which class SimplePie uses for <media:credit>
1230 * Useful when you are overloading or extending SimplePie's default classes.
1232 * @access public
1233 * @param string $class Name of custom class.
1234 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1235 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1237 function set_credit_class($class = 'SimplePie_Credit')
1239 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Credit'))
1241 $this->credit_class = $class;
1242 return true;
1244 return false;
1248 * Allows you to change which class SimplePie uses for <media:rating>
1249 * Useful when you are overloading or extending SimplePie's default classes.
1251 * @access public
1252 * @param string $class Name of custom class.
1253 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1254 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1256 function set_rating_class($class = 'SimplePie_Rating')
1258 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Rating'))
1260 $this->rating_class = $class;
1261 return true;
1263 return false;
1267 * Allows you to change which class SimplePie uses for <media:restriction>
1268 * Useful when you are overloading or extending SimplePie's default classes.
1270 * @access public
1271 * @param string $class Name of custom class.
1272 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1273 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1275 function set_restriction_class($class = 'SimplePie_Restriction')
1277 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Restriction'))
1279 $this->restriction_class = $class;
1280 return true;
1282 return false;
1286 * Allows you to change which class SimplePie uses for content-type sniffing.
1287 * Useful when you are overloading or extending SimplePie's default classes.
1289 * @access public
1290 * @param string $class Name of custom class.
1291 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1292 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1294 function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
1296 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Content_Type_Sniffer'))
1298 $this->content_type_sniffer_class = $class;
1299 return true;
1301 return false;
1305 * Allows you to change which class SimplePie uses item sources.
1306 * Useful when you are overloading or extending SimplePie's default classes.
1308 * @access public
1309 * @param string $class Name of custom class.
1310 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
1311 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
1313 function set_source_class($class = 'SimplePie_Source')
1315 if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Source'))
1317 $this->source_class = $class;
1318 return true;
1320 return false;
1324 * Allows you to override the default user agent string.
1326 * @access public
1327 * @param string $ua New user agent string.
1329 function set_useragent($ua = SIMPLEPIE_USERAGENT)
1331 $this->useragent = (string) $ua;
1335 * Set callback function to create cache filename with
1337 * @access public
1338 * @param mixed $function Callback function
1340 function set_cache_name_function($function = 'md5')
1342 if (is_callable($function))
1344 $this->cache_name_function = $function;
1349 * Set javascript query string parameter
1351 * @access public
1352 * @param mixed $get Javascript query string parameter
1354 function set_javascript($get = 'js')
1356 if ($get)
1358 $this->javascript = (string) $get;
1360 else
1362 $this->javascript = false;
1367 * Set options to make SP as fast as possible. Forgoes a
1368 * substantial amount of data sanitization in favor of speed.
1370 * @access public
1371 * @param bool $set Whether to set them or not
1373 function set_stupidly_fast($set = false)
1375 if ($set)
1377 $this->enable_order_by_date(false);
1378 $this->remove_div(false);
1379 $this->strip_comments(false);
1380 $this->strip_htmltags(false);
1381 $this->strip_attributes(false);
1382 $this->set_image_handler(false);
1387 * Set maximum number of feeds to check with autodiscovery
1389 * @access public
1390 * @param int $max Maximum number of feeds to check
1392 function set_max_checked_feeds($max = 10)
1394 $this->max_checked_feeds = (int) $max;
1397 function remove_div($enable = true)
1399 $this->sanitize->remove_div($enable);
1402 function strip_htmltags($tags = '', $encode = null)
1404 if ($tags === '')
1406 $tags = $this->strip_htmltags;
1408 $this->sanitize->strip_htmltags($tags);
1409 if ($encode !== null)
1411 $this->sanitize->encode_instead_of_strip($tags);
1415 function encode_instead_of_strip($enable = true)
1417 $this->sanitize->encode_instead_of_strip($enable);
1420 function strip_attributes($attribs = '')
1422 if ($attribs === '')
1424 $attribs = $this->strip_attributes;
1426 $this->sanitize->strip_attributes($attribs);
1429 function set_output_encoding($encoding = 'UTF-8')
1431 $this->sanitize->set_output_encoding($encoding);
1434 function strip_comments($strip = false)
1436 $this->sanitize->strip_comments($strip);
1440 * Set element/attribute key/value pairs of HTML attributes
1441 * containing URLs that need to be resolved relative to the feed
1443 * @access public
1444 * @since 1.0
1445 * @param array $element_attribute Element/attribute key/value pairs
1447 function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite'))
1449 $this->sanitize->set_url_replacements($element_attribute);
1453 * Set the handler to enable the display of cached favicons.
1455 * @access public
1456 * @param str $page Web-accessible path to the handler_favicon.php file.
1457 * @param str $qs The query string that the value should be passed to.
1459 function set_favicon_handler($page = false, $qs = 'i')
1461 if ($page !== false)
1463 $this->favicon_handler = $page . '?' . $qs . '=';
1465 else
1467 $this->favicon_handler = '';
1472 * Set the handler to enable the display of cached images.
1474 * @access public
1475 * @param str $page Web-accessible path to the handler_image.php file.
1476 * @param str $qs The query string that the value should be passed to.
1478 function set_image_handler($page = false, $qs = 'i')
1480 if ($page !== false)
1482 $this->sanitize->set_image_handler($page . '?' . $qs . '=');
1484 else
1486 $this->image_handler = '';
1491 * Set the limit for items returned per-feed with multifeeds.
1493 * @access public
1494 * @param integer $limit The maximum number of items to return.
1496 function set_item_limit($limit = 0)
1498 $this->item_limit = (int) $limit;
1501 function init()
1503 // Check absolute bare minimum requirements.
1504 if ((function_exists('version_compare') && version_compare(PHP_VERSION, '4.3.0', '<')) || !extension_loaded('xml') || !extension_loaded('pcre'))
1506 return false;
1508 // 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.
1509 elseif (!extension_loaded('xmlreader'))
1511 static $xml_is_sane = null;
1512 if ($xml_is_sane === null)
1514 $parser_check = xml_parser_create();
1515 xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
1516 xml_parser_free($parser_check);
1517 $xml_is_sane = isset($values[0]['value']);
1519 if (!$xml_is_sane)
1521 return false;
1525 if (isset($_GET[$this->javascript]))
1527 SimplePie_Misc::output_javascript();
1528 exit;
1531 // Pass whatever was set with config options over to the sanitizer.
1532 $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->cache_class);
1533 $this->sanitize->pass_file_data($this->file_class, $this->timeout, $this->useragent, $this->force_fsockopen);
1535 if ($this->feed_url !== null || $this->raw_data !== null)
1537 $this->data = array();
1538 $this->multifeed_objects = array();
1539 $cache = false;
1541 if ($this->feed_url !== null)
1543 $parsed_feed_url = SimplePie_Misc::parse_url($this->feed_url);
1544 // Decide whether to enable caching
1545 if ($this->cache && $parsed_feed_url['scheme'] !== '')
1547 $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc');
1549 // If it's enabled and we don't want an XML dump, use the cache
1550 if ($cache && !$this->xml_dump)
1552 // Load the Cache
1553 $this->data = $cache->load();
1554 if (!empty($this->data))
1556 // If the cache is for an outdated build of SimplePie
1557 if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
1559 $cache->unlink();
1560 $this->data = array();
1562 // If we've hit a collision just rerun it with caching disabled
1563 elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
1565 $cache = false;
1566 $this->data = array();
1568 // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
1569 elseif (isset($this->data['feed_url']))
1571 // If the autodiscovery cache is still valid use it.
1572 if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
1574 // Do not need to do feed autodiscovery yet.
1575 if ($this->data['feed_url'] === $this->data['url'])
1577 $cache->unlink();
1578 $this->data = array();
1580 else
1582 $this->set_feed_url($this->data['feed_url']);
1583 return $this->init();
1587 // Check if the cache has been updated
1588 elseif ($cache->mtime() + $this->cache_duration < time())
1590 // If we have last-modified and/or etag set
1591 if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
1593 $headers = array();
1594 if (isset($this->data['headers']['last-modified']))
1596 $headers['if-modified-since'] = $this->data['headers']['last-modified'];
1598 if (isset($this->data['headers']['etag']))
1600 $headers['if-none-match'] = '"' . $this->data['headers']['etag'] . '"';
1602 $file = new $this->file_class($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen);
1603 if ($file->success)
1605 if ($file->status_code === 304)
1607 $cache->touch();
1608 return true;
1610 else
1612 $headers = $file->headers;
1615 else
1617 unset($file);
1621 // If the cache is still valid, just return true
1622 else
1624 return true;
1627 // If the cache is empty, delete it
1628 else
1630 $cache->unlink();
1631 $this->data = array();
1634 // 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.
1635 if (!isset($file))
1637 if (is_a($this->file, 'SimplePie_File') && $this->file->url === $this->feed_url)
1639 $file =& $this->file;
1641 else
1643 $file = new $this->file_class($this->feed_url, $this->timeout, 5, null, $this->useragent, $this->force_fsockopen);
1646 // If the file connection has an error, set SimplePie::error to that and quit
1647 if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
1649 $this->error = $file->error;
1650 if (!empty($this->data))
1652 return true;
1654 else
1656 return false;
1660 if (!$this->force_feed)
1662 // Check if the supplied URL is a feed, if it isn't, look for it.
1663 $locate = new $this->locator_class($file, $this->timeout, $this->useragent, $this->file_class, $this->max_checked_feeds, $this->content_type_sniffer_class);
1664 if (!$locate->is_feed($file))
1666 // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
1667 unset($file);
1668 if ($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds))
1670 if ($cache)
1672 $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
1673 if (!$cache->save($this))
1675 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);
1677 $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc');
1679 $this->feed_url = $file->url;
1681 else
1683 $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.";
1684 SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
1685 return false;
1688 $locate = null;
1691 $headers = $file->headers;
1692 $data = $file->body;
1693 $sniffer = new $this->content_type_sniffer_class($file);
1694 $sniffed = $sniffer->get_type();
1696 else
1698 $data = $this->raw_data;
1701 // Set up array of possible encodings
1702 $encodings = array();
1704 // First check to see if input has been overridden.
1705 if ($this->input_encoding !== false)
1707 $encodings[] = $this->input_encoding;
1710 $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
1711 $text_types = array('text/xml', 'text/xml-external-parsed-entity');
1713 // RFC 3023 (only applies to sniffed content)
1714 if (isset($sniffed))
1716 if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
1718 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1720 $encodings[] = strtoupper($charset[1]);
1722 $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data));
1723 $encodings[] = 'UTF-8';
1725 elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
1727 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1729 $encodings[] = $charset[1];
1731 $encodings[] = 'US-ASCII';
1733 // Text MIME-type default
1734 elseif (substr($sniffed, 0, 5) === 'text/')
1736 $encodings[] = 'US-ASCII';
1740 // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
1741 $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data));
1742 $encodings[] = 'UTF-8';
1743 $encodings[] = 'ISO-8859-1';
1745 // There's no point in trying an encoding twice
1746 $encodings = array_unique($encodings);
1748 // If we want the XML, just output that with the most likely encoding and quit
1749 if ($this->xml_dump)
1751 header('Content-type: text/xml; charset=' . $encodings[0]);
1752 echo $data;
1753 exit;
1756 // Loop through each possible encoding, till we return something, or run out of possibilities
1757 foreach ($encodings as $encoding)
1759 // Change the encoding to UTF-8 (as we always use UTF-8 internally)
1760 if ($utf8_data = SimplePie_Misc::change_encoding($data, $encoding, 'UTF-8'))
1762 // Create new parser
1763 $parser = new $this->parser_class();
1765 // If it's parsed fine
1766 if ($parser->parse($utf8_data, 'UTF-8'))
1768 $this->data = $parser->get_data();
1769 if ($this->get_type() & ~SIMPLEPIE_TYPE_NONE)
1771 if (isset($headers))
1773 $this->data['headers'] = $headers;
1775 $this->data['build'] = SIMPLEPIE_BUILD;
1777 // Cache the file if caching is enabled
1778 if ($cache && !$cache->save($this))
1780 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);
1782 return true;
1784 else
1786 $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
1787 SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
1788 return false;
1793 if (isset($parser))
1795 // We have an error, just set SimplePie_Misc::error to it and quit
1796 $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());
1798 else
1800 $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.';
1802 SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
1803 return false;
1805 elseif (!empty($this->multifeed_url))
1807 $i = 0;
1808 $success = 0;
1809 $this->multifeed_objects = array();
1810 foreach ($this->multifeed_url as $url)
1812 if (SIMPLEPIE_PHP5)
1814 // This keyword needs to defy coding standards for PHP4 compatibility
1815 $this->multifeed_objects[$i] = clone($this);
1817 else
1819 $this->multifeed_objects[$i] = $this;
1821 $this->multifeed_objects[$i]->set_feed_url($url);
1822 $success |= $this->multifeed_objects[$i]->init();
1823 $i++;
1825 return (bool) $success;
1827 else
1829 return false;
1834 * Return the error message for the occured error
1836 * @access public
1837 * @return string Error message
1839 function error()
1841 return $this->error;
1844 function get_encoding()
1846 return $this->sanitize->output_encoding;
1849 function handle_content_type($mime = 'text/html')
1851 if (!headers_sent())
1853 $header = "Content-type: $mime;";
1854 if ($this->get_encoding())
1856 $header .= ' charset=' . $this->get_encoding();
1858 else
1860 $header .= ' charset=UTF-8';
1862 header($header);
1866 function get_type()
1868 if (!isset($this->data['type']))
1870 $this->data['type'] = SIMPLEPIE_TYPE_ALL;
1871 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
1873 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
1875 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
1877 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
1879 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
1881 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
1882 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
1883 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
1884 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
1886 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
1888 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
1889 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
1890 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
1891 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
1893 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
1896 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
1898 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
1899 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1901 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1903 case '0.91':
1904 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
1905 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1907 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1909 case '0':
1910 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
1911 break;
1913 case '24':
1914 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
1915 break;
1918 break;
1920 case '0.92':
1921 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
1922 break;
1924 case '0.93':
1925 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
1926 break;
1928 case '0.94':
1929 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
1930 break;
1932 case '2.0':
1933 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
1934 break;
1938 else
1940 $this->data['type'] = SIMPLEPIE_TYPE_NONE;
1943 return $this->data['type'];
1947 * Returns the URL for the favicon of the feed's website.
1949 * @todo Cache atom:icon
1950 * @access public
1951 * @since 1.0
1953 function get_favicon()
1955 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
1957 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
1959 elseif (($url = $this->get_link()) !== null && preg_match('/^http(s)?:\/\//i', $url))
1961 $favicon = SimplePie_Misc::absolutize_url('/favicon.ico', $url);
1963 if ($this->cache && $this->favicon_handler)
1965 $favicon_filename = call_user_func($this->cache_name_function, $favicon);
1966 $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $favicon_filename, 'spi');
1968 if ($cache->load())
1970 return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI);
1972 else
1974 $file = new $this->file_class($favicon, $this->timeout / 10, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen);
1976 if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)) && strlen($file->body) > 0)
1978 $sniffer = new $this->content_type_sniffer_class($file);
1979 if (substr($sniffer->get_type(), 0, 6) === 'image/')
1981 if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
1983 return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI);
1985 else
1987 trigger_error("$cache->name is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
1988 return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI);
1991 // not an image
1992 else
1994 return false;
1999 else
2001 return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI);
2004 return false;
2008 * @todo If we have a perm redirect we should return the new URL
2009 * @todo When we make the above change, let's support <itunes:new-feed-url> as well
2010 * @todo Also, |atom:link|@rel=self
2012 function subscribe_url()
2014 if ($this->feed_url !== null)
2016 return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
2018 else
2020 return null;
2024 function subscribe_feed()
2026 if ($this->feed_url !== null)
2028 return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI);
2030 else
2032 return null;
2036 function subscribe_outlook()
2038 if ($this->feed_url !== null)
2040 return $this->sanitize('outlook' . SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI);
2042 else
2044 return null;
2048 function subscribe_podcast()
2050 if ($this->feed_url !== null)
2052 return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 3), SIMPLEPIE_CONSTRUCT_IRI);
2054 else
2056 return null;
2060 function subscribe_itunes()
2062 if ($this->feed_url !== null)
2064 return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 4), SIMPLEPIE_CONSTRUCT_IRI);
2066 else
2068 return null;
2073 * Creates the subscribe_* methods' return data
2075 * @access private
2076 * @param string $feed_url String to prefix to the feed URL
2077 * @param string $site_url String to prefix to the site URL (and
2078 * suffix to the feed URL)
2079 * @return mixed URL if feed exists, false otherwise
2081 function subscribe_service($feed_url, $site_url = null)
2083 if ($this->subscribe_url())
2085 $return = $feed_url . rawurlencode($this->feed_url);
2086 if ($site_url !== null && $this->get_link() !== null)
2088 $return .= $site_url . rawurlencode($this->get_link());
2090 return $this->sanitize($return, SIMPLEPIE_CONSTRUCT_IRI);
2092 else
2094 return null;
2098 function subscribe_aol()
2100 return $this->subscribe_service('http://feeds.my.aol.com/add.jsp?url=');
2103 function subscribe_bloglines()
2105 return $this->subscribe_service('http://www.bloglines.com/sub/');
2108 function subscribe_eskobo()
2110 return $this->subscribe_service('http://www.eskobo.com/?AddToMyPage=');
2113 function subscribe_feedfeeds()
2115 return $this->subscribe_service('http://www.feedfeeds.com/add?feed=');
2118 function subscribe_feedster()
2120 return $this->subscribe_service('http://www.feedster.com/myfeedster.php?action=addrss&confirm=no&rssurl=');
2123 function subscribe_google()
2125 return $this->subscribe_service('http://fusion.google.com/add?feedurl=');
2128 function subscribe_gritwire()
2130 return $this->subscribe_service('http://my.gritwire.com/feeds/addExternalFeed.aspx?FeedUrl=');
2133 function subscribe_msn()
2135 return $this->subscribe_service('http://my.msn.com/addtomymsn.armx?id=rss&ut=', '&ru=');
2138 function subscribe_netvibes()
2140 return $this->subscribe_service('http://www.netvibes.com/subscribe.php?url=');
2143 function subscribe_newsburst()
2145 return $this->subscribe_service('http://www.newsburst.com/Source/?add=');
2148 function subscribe_newsgator()
2150 return $this->subscribe_service('http://www.newsgator.com/ngs/subscriber/subext.aspx?url=');
2153 function subscribe_odeo()
2155 return $this->subscribe_service('http://www.odeo.com/listen/subscribe?feed=');
2158 function subscribe_podnova()
2160 return $this->subscribe_service('http://www.podnova.com/index_your_podcasts.srf?action=add&url=');
2163 function subscribe_rojo()
2165 return $this->subscribe_service('http://www.rojo.com/add-subscription?resource=');
2168 function subscribe_yahoo()
2170 return $this->subscribe_service('http://add.my.yahoo.com/rss?url=');
2173 function get_feed_tags($namespace, $tag)
2175 $type = $this->get_type();
2176 if ($type & SIMPLEPIE_TYPE_ATOM_10)
2178 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
2180 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
2183 if ($type & SIMPLEPIE_TYPE_ATOM_03)
2185 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
2187 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
2190 if ($type & SIMPLEPIE_TYPE_RSS_RDF)
2192 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
2194 return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
2197 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
2199 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
2201 return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
2204 return null;
2207 function get_channel_tags($namespace, $tag)
2209 $type = $this->get_type();
2210 if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
2212 if ($return = $this->get_feed_tags($namespace, $tag))
2214 return $return;
2217 if ($type & SIMPLEPIE_TYPE_RSS_10)
2219 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
2221 if (isset($channel[0]['child'][$namespace][$tag]))
2223 return $channel[0]['child'][$namespace][$tag];
2227 if ($type & SIMPLEPIE_TYPE_RSS_090)
2229 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
2231 if (isset($channel[0]['child'][$namespace][$tag]))
2233 return $channel[0]['child'][$namespace][$tag];
2237 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
2239 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
2241 if (isset($channel[0]['child'][$namespace][$tag]))
2243 return $channel[0]['child'][$namespace][$tag];
2247 return null;
2250 function get_image_tags($namespace, $tag)
2252 $type = $this->get_type();
2253 if ($type & SIMPLEPIE_TYPE_RSS_10)
2255 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
2257 if (isset($image[0]['child'][$namespace][$tag]))
2259 return $image[0]['child'][$namespace][$tag];
2263 if ($type & SIMPLEPIE_TYPE_RSS_090)
2265 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
2267 if (isset($image[0]['child'][$namespace][$tag]))
2269 return $image[0]['child'][$namespace][$tag];
2273 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
2275 if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
2277 if (isset($image[0]['child'][$namespace][$tag]))
2279 return $image[0]['child'][$namespace][$tag];
2283 return null;
2286 function get_base($element = array())
2288 if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
2290 return $element['xml_base'];
2292 elseif ($this->get_link() !== null)
2294 return $this->get_link();
2296 else
2298 return $this->subscribe_url();
2302 function sanitize($data, $type, $base = '')
2304 return $this->sanitize->sanitize($data, $type, $base);
2307 function get_title()
2309 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
2311 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2313 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
2315 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2317 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2319 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2321 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2323 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2325 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
2327 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2329 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2331 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2333 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2335 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2337 else
2339 return null;
2343 function get_category($key = 0)
2345 $categories = $this->get_categories();
2346 if (isset($categories[$key]))
2348 return $categories[$key];
2350 else
2352 return null;
2356 function get_categories()
2358 $categories = array();
2360 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
2362 $term = null;
2363 $scheme = null;
2364 $label = null;
2365 if (isset($category['attribs']['']['term']))
2367 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
2369 if (isset($category['attribs']['']['scheme']))
2371 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2373 if (isset($category['attribs']['']['label']))
2375 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
2377 $categories[] = new $this->category_class($term, $scheme, $label);
2379 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
2381 // This is really the label, but keep this as the term also for BC.
2382 // Label will also work on retrieving because that falls back to term.
2383 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2384 if (isset($category['attribs']['']['domain']))
2386 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
2388 else
2390 $scheme = null;
2392 $categories[] = new $this->category_class($term, $scheme, null);
2394 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
2396 $categories[] = new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2398 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
2400 $categories[] = new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2403 if (!empty($categories))
2405 return SimplePie_Misc::array_unique($categories);
2407 else
2409 return null;
2413 function get_author($key = 0)
2415 $authors = $this->get_authors();
2416 if (isset($authors[$key]))
2418 return $authors[$key];
2420 else
2422 return null;
2426 function get_authors()
2428 $authors = array();
2429 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
2431 $name = null;
2432 $uri = null;
2433 $email = null;
2434 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2436 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2438 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2440 $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]));
2442 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2444 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2446 if ($name !== null || $email !== null || $uri !== null)
2448 $authors[] = new $this->author_class($name, $uri, $email);
2451 if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
2453 $name = null;
2454 $url = null;
2455 $email = null;
2456 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2458 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2460 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2462 $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]));
2464 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2466 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2468 if ($name !== null || $email !== null || $url !== null)
2470 $authors[] = new $this->author_class($name, $url, $email);
2473 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
2475 $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2477 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
2479 $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2481 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
2483 $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
2486 if (!empty($authors))
2488 return SimplePie_Misc::array_unique($authors);
2490 else
2492 return null;
2496 function get_contributor($key = 0)
2498 $contributors = $this->get_contributors();
2499 if (isset($contributors[$key]))
2501 return $contributors[$key];
2503 else
2505 return null;
2509 function get_contributors()
2511 $contributors = array();
2512 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
2514 $name = null;
2515 $uri = null;
2516 $email = null;
2517 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2519 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2521 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2523 $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]));
2525 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2527 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2529 if ($name !== null || $email !== null || $uri !== null)
2531 $contributors[] = new $this->author_class($name, $uri, $email);
2534 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
2536 $name = null;
2537 $url = null;
2538 $email = null;
2539 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2541 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2543 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2545 $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]));
2547 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2549 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2551 if ($name !== null || $email !== null || $url !== null)
2553 $contributors[] = new $this->author_class($name, $url, $email);
2557 if (!empty($contributors))
2559 return SimplePie_Misc::array_unique($contributors);
2561 else
2563 return null;
2567 function get_link($key = 0, $rel = 'alternate')
2569 $links = $this->get_links($rel);
2570 if (isset($links[$key]))
2572 return $links[$key];
2574 else
2576 return null;
2581 * Added for parity between the parent-level and the item/entry-level.
2583 function get_permalink()
2585 return $this->get_link(0);
2588 function get_links($rel = 'alternate')
2590 if (!isset($this->data['links']))
2592 $this->data['links'] = array();
2593 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
2595 foreach ($links as $link)
2597 if (isset($link['attribs']['']['href']))
2599 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2600 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2604 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
2606 foreach ($links as $link)
2608 if (isset($link['attribs']['']['href']))
2610 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2611 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2616 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2618 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2620 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2622 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2624 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2626 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2629 $keys = array_keys($this->data['links']);
2630 foreach ($keys as $key)
2632 if (SimplePie_Misc::is_isegment_nz_nc($key))
2634 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
2636 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
2637 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
2639 else
2641 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
2644 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
2646 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
2648 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
2652 if (isset($this->data['links'][$rel]))
2654 return $this->data['links'][$rel];
2656 else
2658 return null;
2662 function get_all_discovered_feeds()
2664 return $this->all_discovered_feeds;
2667 function get_description()
2669 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
2671 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2673 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
2675 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2677 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
2679 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2681 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
2683 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2685 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
2687 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2689 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
2691 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2693 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
2695 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2697 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
2699 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2701 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
2703 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2705 else
2707 return null;
2711 function get_copyright()
2713 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
2715 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2717 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
2719 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
2721 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
2723 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2725 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
2727 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2729 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
2731 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2733 else
2735 return null;
2739 function get_language()
2741 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
2743 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2745 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
2747 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2749 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
2751 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2753 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
2755 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2757 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
2759 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2761 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
2763 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2765 elseif (isset($this->data['headers']['content-language']))
2767 return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
2769 else
2771 return null;
2775 function get_latitude()
2778 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
2780 return (float) $return[0]['data'];
2782 elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
2784 return (float) $match[1];
2786 else
2788 return null;
2792 function get_longitude()
2794 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
2796 return (float) $return[0]['data'];
2798 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
2800 return (float) $return[0]['data'];
2802 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))
2804 return (float) $match[2];
2806 else
2808 return null;
2812 function get_image_title()
2814 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2816 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2818 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2820 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2822 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
2824 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2826 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2828 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2830 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2832 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2834 else
2836 return null;
2840 function get_image_url()
2842 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
2844 return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
2846 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
2848 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2850 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
2852 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2854 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
2856 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2858 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
2860 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2862 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2864 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2866 else
2868 return null;
2872 function get_image_link()
2874 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2876 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2878 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2880 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2882 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2884 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2886 else
2888 return null;
2892 function get_image_width()
2894 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
2896 return round($return[0]['data']);
2898 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2900 return 88.0;
2902 else
2904 return null;
2908 function get_image_height()
2910 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
2912 return round($return[0]['data']);
2914 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2916 return 31.0;
2918 else
2920 return null;
2924 function get_item_quantity($max = 0)
2926 $max = (int) $max;
2927 $qty = count($this->get_items());
2928 if ($max === 0)
2930 return $qty;
2932 else
2934 return ($qty > $max) ? $max : $qty;
2938 function get_item($key = 0)
2940 $items = $this->get_items();
2941 if (isset($items[$key]))
2943 return $items[$key];
2945 else
2947 return null;
2951 function get_items($start = 0, $end = 0)
2953 if (!isset($this->data['items']))
2955 if (!empty($this->multifeed_objects))
2957 $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
2959 else
2961 $this->data['items'] = array();
2962 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
2964 $keys = array_keys($items);
2965 foreach ($keys as $key)
2967 $this->data['items'][] = new $this->item_class($this, $items[$key]);
2970 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
2972 $keys = array_keys($items);
2973 foreach ($keys as $key)
2975 $this->data['items'][] = new $this->item_class($this, $items[$key]);
2978 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
2980 $keys = array_keys($items);
2981 foreach ($keys as $key)
2983 $this->data['items'][] = new $this->item_class($this, $items[$key]);
2986 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
2988 $keys = array_keys($items);
2989 foreach ($keys as $key)
2991 $this->data['items'][] = new $this->item_class($this, $items[$key]);
2994 if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
2996 $keys = array_keys($items);
2997 foreach ($keys as $key)
2999 $this->data['items'][] = new $this->item_class($this, $items[$key]);
3005 if (!empty($this->data['items']))
3007 // If we want to order it by date, check if all items have a date, and then sort it
3008 if ($this->order_by_date && empty($this->multifeed_objects))
3010 if (!isset($this->data['ordered_items']))
3012 $do_sort = true;
3013 foreach ($this->data['items'] as $item)
3015 if (!$item->get_date('U'))
3017 $do_sort = false;
3018 break;
3021 $item = null;
3022 $this->data['ordered_items'] = $this->data['items'];
3023 if ($do_sort)
3025 usort($this->data['ordered_items'], array(&$this, 'sort_items'));
3028 $items = $this->data['ordered_items'];
3030 else
3032 $items = $this->data['items'];
3035 // Slice the data as desired
3036 if ($end === 0)
3038 return array_slice($items, $start);
3040 else
3042 return array_slice($items, $start, $end);
3045 else
3047 return array();
3052 * @static
3054 function sort_items($a, $b)
3056 return $a->get_date('U') <= $b->get_date('U');
3060 * @static
3062 function merge_items($urls, $start = 0, $end = 0, $limit = 0)
3064 if (is_array($urls) && sizeof($urls) > 0)
3066 $items = array();
3067 foreach ($urls as $arg)
3069 if (is_a($arg, 'SimplePie'))
3071 $items = array_merge($items, $arg->get_items(0, $limit));
3073 else
3075 trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
3079 $do_sort = true;
3080 foreach ($items as $item)
3082 if (!$item->get_date('U'))
3084 $do_sort = false;
3085 break;
3088 $item = null;
3089 if ($do_sort)
3091 usort($items, array('SimplePie', 'sort_items'));
3094 if ($end === 0)
3096 return array_slice($items, $start);
3098 else
3100 return array_slice($items, $start, $end);
3103 else
3105 trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
3106 return array();
3111 class SimplePie_Item
3113 var $feed;
3114 var $data = array();
3116 function SimplePie_Item($feed, $data)
3118 $this->feed = $feed;
3119 $this->data = $data;
3122 function __toString()
3124 return md5(serialize($this->data));
3128 * Remove items that link back to this before destroying this object
3130 function __destruct()
3132 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
3134 unset($this->feed);
3138 function get_item_tags($namespace, $tag)
3140 if (isset($this->data['child'][$namespace][$tag]))
3142 return $this->data['child'][$namespace][$tag];
3144 else
3146 return null;
3150 function get_base($element = array())
3152 return $this->feed->get_base($element);
3155 function sanitize($data, $type, $base = '')
3157 return $this->feed->sanitize($data, $type, $base);
3160 function get_feed()
3162 return $this->feed;
3165 function get_id($hash = false)
3167 if (!$hash)
3169 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
3171 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3173 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
3175 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3177 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
3179 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3181 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
3183 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3185 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
3187 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3189 elseif (($return = $this->get_permalink()) !== null)
3191 return $return;
3193 elseif (($return = $this->get_title()) !== null)
3195 return $return;
3198 if ($this->get_permalink() !== null || $this->get_title() !== null)
3200 return md5($this->get_permalink() . $this->get_title());
3202 else
3204 return md5(serialize($this->data));
3208 function get_title()
3210 if (!isset($this->data['title']))
3212 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
3214 $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3216 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
3218 $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3220 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
3222 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
3224 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
3226 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
3228 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
3230 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
3232 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
3234 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3236 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
3238 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3240 else
3242 $this->data['title'] = null;
3245 return $this->data['title'];
3248 function get_description($description_only = false)
3250 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
3252 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3254 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
3256 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3258 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
3260 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
3262 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
3264 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
3266 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
3268 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3270 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
3272 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3274 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
3276 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
3278 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
3280 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3282 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
3284 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
3287 elseif (!$description_only)
3289 return $this->get_content(true);
3291 else
3293 return null;
3297 function get_content($content_only = false)
3299 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
3301 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_content_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3303 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
3305 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3307 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
3309 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
3311 elseif (!$content_only)
3313 return $this->get_description(true);
3315 else
3317 return null;
3321 function get_category($key = 0)
3323 $categories = $this->get_categories();
3324 if (isset($categories[$key]))
3326 return $categories[$key];
3328 else
3330 return null;
3334 function get_categories()
3336 $categories = array();
3338 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
3340 $term = null;
3341 $scheme = null;
3342 $label = null;
3343 if (isset($category['attribs']['']['term']))
3345 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
3347 if (isset($category['attribs']['']['scheme']))
3349 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
3351 if (isset($category['attribs']['']['label']))
3353 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
3355 $categories[] = new $this->feed->category_class($term, $scheme, $label);
3357 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
3359 // This is really the label, but keep this as the term also for BC.
3360 // Label will also work on retrieving because that falls back to term.
3361 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3362 if (isset($category['attribs']['']['domain']))
3364 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
3366 else
3368 $scheme = null;
3370 $categories[] = new $this->feed->category_class($term, $scheme, null);
3372 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
3374 $categories[] = new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
3376 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
3378 $categories[] = new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
3381 if (!empty($categories))
3383 return SimplePie_Misc::array_unique($categories);
3385 else
3387 return null;
3391 function get_author($key = 0)
3393 $authors = $this->get_authors();
3394 if (isset($authors[$key]))
3396 return $authors[$key];
3398 else
3400 return null;
3404 function get_contributor($key = 0)
3406 $contributors = $this->get_contributors();
3407 if (isset($contributors[$key]))
3409 return $contributors[$key];
3411 else
3413 return null;
3417 function get_contributors()
3419 $contributors = array();
3420 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
3422 $name = null;
3423 $uri = null;
3424 $email = null;
3425 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
3427 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3429 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
3431 $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]));
3433 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
3435 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3437 if ($name !== null || $email !== null || $uri !== null)
3439 $contributors[] = new $this->feed->author_class($name, $uri, $email);
3442 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
3444 $name = null;
3445 $url = null;
3446 $email = null;
3447 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
3449 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3451 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
3453 $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]));
3455 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
3457 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3459 if ($name !== null || $email !== null || $url !== null)
3461 $contributors[] = new $this->feed->author_class($name, $url, $email);
3465 if (!empty($contributors))
3467 return SimplePie_Misc::array_unique($contributors);
3469 else
3471 return null;
3475 function get_authors()
3477 $authors = array();
3478 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
3480 $name = null;
3481 $uri = null;
3482 $email = null;
3483 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
3485 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3487 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
3489 $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]));
3491 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
3493 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3495 if ($name !== null || $email !== null || $uri !== null)
3497 $authors[] = new $this->feed->author_class($name, $uri, $email);
3500 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
3502 $name = null;
3503 $url = null;
3504 $email = null;
3505 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
3507 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3509 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
3511 $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]));
3513 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
3515 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3517 if ($name !== null || $email !== null || $url !== null)
3519 $authors[] = new $this->feed->author_class($name, $url, $email);
3522 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
3524 $authors[] = new $this->feed->author_class(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
3526 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
3528 $authors[] = new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
3530 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
3532 $authors[] = new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
3534 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
3536 $authors[] = new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
3539 if (!empty($authors))
3541 return SimplePie_Misc::array_unique($authors);
3543 elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
3545 return $authors;
3547 elseif ($authors = $this->feed->get_authors())
3549 return $authors;
3551 else
3553 return null;
3557 function get_copyright()
3559 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
3561 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
3563 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
3565 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3567 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
3569 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3571 else
3573 return null;
3577 function get_date($date_format = 'j F Y, g:i a')
3579 if (!isset($this->data['date']))
3581 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
3583 $this->data['date']['raw'] = $return[0]['data'];
3585 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
3587 $this->data['date']['raw'] = $return[0]['data'];
3589 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
3591 $this->data['date']['raw'] = $return[0]['data'];
3593 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
3595 $this->data['date']['raw'] = $return[0]['data'];
3597 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
3599 $this->data['date']['raw'] = $return[0]['data'];
3601 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
3603 $this->data['date']['raw'] = $return[0]['data'];
3605 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
3607 $this->data['date']['raw'] = $return[0]['data'];
3609 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
3611 $this->data['date']['raw'] = $return[0]['data'];
3614 if (!empty($this->data['date']['raw']))
3616 $parser = SimplePie_Parse_Date::get();
3617 $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
3619 else
3621 $this->data['date'] = null;
3624 if ($this->data['date'])
3626 $date_format = (string) $date_format;
3627 switch ($date_format)
3629 case '':
3630 return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
3632 case 'U':
3633 return $this->data['date']['parsed'];
3635 default:
3636 return date($date_format, $this->data['date']['parsed']);
3639 else
3641 return null;
3645 function get_local_date($date_format = '%c')
3647 if (!$date_format)
3649 return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
3651 elseif (($date = $this->get_date('U')) !== null && $date !== false)
3653 return strftime($date_format, $date);
3655 else
3657 return null;
3661 function get_permalink()
3663 $link = $this->get_link();
3664 $enclosure = $this->get_enclosure(0);
3665 if ($link !== null)
3667 return $link;
3669 elseif ($enclosure !== null)
3671 return $enclosure->get_link();
3673 else
3675 return null;
3679 function get_link($key = 0, $rel = 'alternate')
3681 $links = $this->get_links($rel);
3682 if ($links[$key] !== null)
3684 return $links[$key];
3686 else
3688 return null;
3692 function get_links($rel = 'alternate')
3694 if (!isset($this->data['links']))
3696 $this->data['links'] = array();
3697 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
3699 if (isset($link['attribs']['']['href']))
3701 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
3702 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
3706 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
3708 if (isset($link['attribs']['']['href']))
3710 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
3711 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
3714 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
3716 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
3718 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
3720 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
3722 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
3724 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
3726 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
3728 if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true')
3730 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
3734 $keys = array_keys($this->data['links']);
3735 foreach ($keys as $key)
3737 if (SimplePie_Misc::is_isegment_nz_nc($key))
3739 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
3741 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
3742 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
3744 else
3746 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
3749 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
3751 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
3753 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
3756 if (isset($this->data['links'][$rel]))
3758 return $this->data['links'][$rel];
3760 else
3762 return null;
3767 * @todo Add ability to prefer one type of content over another (in a media group).
3769 function get_enclosure($key = 0, $prefer = null)
3771 $enclosures = $this->get_enclosures();
3772 if (isset($enclosures[$key]))
3774 return $enclosures[$key];
3776 else
3778 return null;
3783 * Grabs all available enclosures (podcasts, etc.)
3785 * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
3787 * At this point, we're pretty much assuming that all enclosures for an item are the same content. Anything else is too complicated to properly support.
3789 * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
3790 * @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).
3792 function get_enclosures()
3794 if (!isset($this->data['enclosures']))
3796 $this->data['enclosures'] = array();
3798 // Elements
3799 $captions_parent = null;
3800 $categories_parent = null;
3801 $copyrights_parent = null;
3802 $credits_parent = null;
3803 $description_parent = null;
3804 $duration_parent = null;
3805 $hashes_parent = null;
3806 $keywords_parent = null;
3807 $player_parent = null;
3808 $ratings_parent = null;
3809 $restrictions_parent = null;
3810 $thumbnails_parent = null;
3811 $title_parent = null;
3813 // Let's do the channel and item-level ones first, and just re-use them if we need to.
3814 $parent = $this->get_feed();
3816 // CAPTIONS
3817 if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
3819 foreach ($captions as $caption)
3821 $caption_type = null;
3822 $caption_lang = null;
3823 $caption_startTime = null;
3824 $caption_endTime = null;
3825 $caption_text = null;
3826 if (isset($caption['attribs']['']['type']))
3828 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
3830 if (isset($caption['attribs']['']['lang']))
3832 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
3834 if (isset($caption['attribs']['']['start']))
3836 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
3838 if (isset($caption['attribs']['']['end']))
3840 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
3842 if (isset($caption['data']))
3844 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3846 $captions_parent[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
3849 elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
3851 foreach ($captions as $caption)
3853 $caption_type = null;
3854 $caption_lang = null;
3855 $caption_startTime = null;
3856 $caption_endTime = null;
3857 $caption_text = null;
3858 if (isset($caption['attribs']['']['type']))
3860 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
3862 if (isset($caption['attribs']['']['lang']))
3864 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
3866 if (isset($caption['attribs']['']['start']))
3868 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
3870 if (isset($caption['attribs']['']['end']))
3872 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
3874 if (isset($caption['data']))
3876 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3878 $captions_parent[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
3881 if (is_array($captions_parent))
3883 $captions_parent = array_values(SimplePie_Misc::array_unique($captions_parent));
3886 // CATEGORIES
3887 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
3889 $term = null;
3890 $scheme = null;
3891 $label = null;
3892 if (isset($category['data']))
3894 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3896 if (isset($category['attribs']['']['scheme']))
3898 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
3900 else
3902 $scheme = 'http://search.yahoo.com/mrss/category_schema';
3904 if (isset($category['attribs']['']['label']))
3906 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
3908 $categories_parent[] = new $this->feed->category_class($term, $scheme, $label);
3910 foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
3912 $term = null;
3913 $scheme = null;
3914 $label = null;
3915 if (isset($category['data']))
3917 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3919 if (isset($category['attribs']['']['scheme']))
3921 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
3923 else
3925 $scheme = 'http://search.yahoo.com/mrss/category_schema';
3927 if (isset($category['attribs']['']['label']))
3929 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
3931 $categories_parent[] = new $this->feed->category_class($term, $scheme, $label);
3933 foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
3935 $term = null;
3936 $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
3937 $label = null;
3938 if (isset($category['attribs']['']['text']))
3940 $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
3942 $categories_parent[] = new $this->feed->category_class($term, $scheme, $label);
3944 if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
3946 foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory)
3948 if (isset($subcategory['attribs']['']['text']))
3950 $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
3952 $categories_parent[] = new $this->feed->category_class($term, $scheme, $label);
3956 if (is_array($categories_parent))
3958 $categories_parent = array_values(SimplePie_Misc::array_unique($categories_parent));
3961 // COPYRIGHT
3962 if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
3964 $copyright_url = null;
3965 $copyright_label = null;
3966 if (isset($copyright[0]['attribs']['']['url']))
3968 $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
3970 if (isset($copyright[0]['data']))
3972 $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3974 $copyrights_parent = new $this->feed->copyright_class($copyright_url, $copyright_label);
3976 elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
3978 $copyright_url = null;
3979 $copyright_label = null;
3980 if (isset($copyright[0]['attribs']['']['url']))
3982 $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
3984 if (isset($copyright[0]['data']))
3986 $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
3988 $copyrights_parent = new $this->feed->copyright_class($copyright_url, $copyright_label);
3991 // CREDITS
3992 if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
3994 foreach ($credits as $credit)
3996 $credit_role = null;
3997 $credit_scheme = null;
3998 $credit_name = null;
3999 if (isset($credit['attribs']['']['role']))
4001 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
4003 if (isset($credit['attribs']['']['scheme']))
4005 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4007 else
4009 $credit_scheme = 'urn:ebu';
4011 if (isset($credit['data']))
4013 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4015 $credits_parent[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
4018 elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
4020 foreach ($credits as $credit)
4022 $credit_role = null;
4023 $credit_scheme = null;
4024 $credit_name = null;
4025 if (isset($credit['attribs']['']['role']))
4027 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
4029 if (isset($credit['attribs']['']['scheme']))
4031 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4033 else
4035 $credit_scheme = 'urn:ebu';
4037 if (isset($credit['data']))
4039 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4041 $credits_parent[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
4044 if (is_array($credits_parent))
4046 $credits_parent = array_values(SimplePie_Misc::array_unique($credits_parent));
4049 // DESCRIPTION
4050 if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
4052 if (isset($description_parent[0]['data']))
4054 $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4057 elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
4059 if (isset($description_parent[0]['data']))
4061 $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4065 // DURATION
4066 if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration'))
4068 $seconds = null;
4069 $minutes = null;
4070 $hours = null;
4071 if (isset($duration_parent[0]['data']))
4073 $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4074 if (sizeof($temp) > 0)
4076 $seconds = (int) array_pop($temp);
4078 if (sizeof($temp) > 0)
4080 $minutes = (int) array_pop($temp);
4081 $seconds += $minutes * 60;
4083 if (sizeof($temp) > 0)
4085 $hours = (int) array_pop($temp);
4086 $seconds += $hours * 3600;
4088 unset($temp);
4089 $duration_parent = $seconds;
4093 // HASHES
4094 if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
4096 foreach ($hashes_iterator as $hash)
4098 $value = null;
4099 $algo = null;
4100 if (isset($hash['data']))
4102 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4104 if (isset($hash['attribs']['']['algo']))
4106 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
4108 else
4110 $algo = 'md5';
4112 $hashes_parent[] = $algo.':'.$value;
4115 elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
4117 foreach ($hashes_iterator as $hash)
4119 $value = null;
4120 $algo = null;
4121 if (isset($hash['data']))
4123 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4125 if (isset($hash['attribs']['']['algo']))
4127 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
4129 else
4131 $algo = 'md5';
4133 $hashes_parent[] = $algo.':'.$value;
4136 if (is_array($hashes_parent))
4138 $hashes_parent = array_values(SimplePie_Misc::array_unique($hashes_parent));
4141 // KEYWORDS
4142 if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
4144 if (isset($keywords[0]['data']))
4146 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4147 foreach ($temp as $word)
4149 $keywords_parent[] = trim($word);
4152 unset($temp);
4154 elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
4156 if (isset($keywords[0]['data']))
4158 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4159 foreach ($temp as $word)
4161 $keywords_parent[] = trim($word);
4164 unset($temp);
4166 elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
4168 if (isset($keywords[0]['data']))
4170 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4171 foreach ($temp as $word)
4173 $keywords_parent[] = trim($word);
4176 unset($temp);
4178 elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
4180 if (isset($keywords[0]['data']))
4182 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4183 foreach ($temp as $word)
4185 $keywords_parent[] = trim($word);
4188 unset($temp);
4190 if (is_array($keywords_parent))
4192 $keywords_parent = array_values(SimplePie_Misc::array_unique($keywords_parent));
4195 // PLAYER
4196 if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
4198 if (isset($player_parent[0]['attribs']['']['url']))
4200 $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4203 elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
4205 if (isset($player_parent[0]['attribs']['']['url']))
4207 $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4211 // RATINGS
4212 if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
4214 foreach ($ratings as $rating)
4216 $rating_scheme = null;
4217 $rating_value = null;
4218 if (isset($rating['attribs']['']['scheme']))
4220 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4222 else
4224 $rating_scheme = 'urn:simple';
4226 if (isset($rating['data']))
4228 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4230 $ratings_parent[] = new $this->feed->rating_class($rating_scheme, $rating_value);
4233 elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
4235 foreach ($ratings as $rating)
4237 $rating_scheme = 'urn:itunes';
4238 $rating_value = null;
4239 if (isset($rating['data']))
4241 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4243 $ratings_parent[] = new $this->feed->rating_class($rating_scheme, $rating_value);
4246 elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
4248 foreach ($ratings as $rating)
4250 $rating_scheme = null;
4251 $rating_value = null;
4252 if (isset($rating['attribs']['']['scheme']))
4254 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4256 else
4258 $rating_scheme = 'urn:simple';
4260 if (isset($rating['data']))
4262 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4264 $ratings_parent[] = new $this->feed->rating_class($rating_scheme, $rating_value);
4267 elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
4269 foreach ($ratings as $rating)
4271 $rating_scheme = 'urn:itunes';
4272 $rating_value = null;
4273 if (isset($rating['data']))
4275 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4277 $ratings_parent[] = new $this->feed->rating_class($rating_scheme, $rating_value);
4280 if (is_array($ratings_parent))
4282 $ratings_parent = array_values(SimplePie_Misc::array_unique($ratings_parent));
4285 // RESTRICTIONS
4286 if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
4288 foreach ($restrictions as $restriction)
4290 $restriction_relationship = null;
4291 $restriction_type = null;
4292 $restriction_value = null;
4293 if (isset($restriction['attribs']['']['relationship']))
4295 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
4297 if (isset($restriction['attribs']['']['type']))
4299 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4301 if (isset($restriction['data']))
4303 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4305 $restrictions_parent[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
4308 elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
4310 foreach ($restrictions as $restriction)
4312 $restriction_relationship = 'allow';
4313 $restriction_type = null;
4314 $restriction_value = 'itunes';
4315 if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
4317 $restriction_relationship = 'deny';
4319 $restrictions_parent[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
4322 elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
4324 foreach ($restrictions as $restriction)
4326 $restriction_relationship = null;
4327 $restriction_type = null;
4328 $restriction_value = null;
4329 if (isset($restriction['attribs']['']['relationship']))
4331 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
4333 if (isset($restriction['attribs']['']['type']))
4335 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4337 if (isset($restriction['data']))
4339 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4341 $restrictions_parent[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
4344 elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
4346 foreach ($restrictions as $restriction)
4348 $restriction_relationship = 'allow';
4349 $restriction_type = null;
4350 $restriction_value = 'itunes';
4351 if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
4353 $restriction_relationship = 'deny';
4355 $restrictions_parent[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
4358 if (is_array($restrictions_parent))
4360 $restrictions_parent = array_values(SimplePie_Misc::array_unique($restrictions_parent));
4363 // THUMBNAILS
4364 if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
4366 foreach ($thumbnails as $thumbnail)
4368 if (isset($thumbnail['attribs']['']['url']))
4370 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4374 elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
4376 foreach ($thumbnails as $thumbnail)
4378 if (isset($thumbnail['attribs']['']['url']))
4380 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4385 // TITLES
4386 if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
4388 if (isset($title_parent[0]['data']))
4390 $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4393 elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
4395 if (isset($title_parent[0]['data']))
4397 $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4401 // Clear the memory
4402 unset($parent);
4404 // Attributes
4405 $bitrate = null;
4406 $channels = null;
4407 $duration = null;
4408 $expression = null;
4409 $framerate = null;
4410 $height = null;
4411 $javascript = null;
4412 $lang = null;
4413 $length = null;
4414 $medium = null;
4415 $samplingrate = null;
4416 $type = null;
4417 $url = null;
4418 $width = null;
4420 // Elements
4421 $captions = null;
4422 $categories = null;
4423 $copyrights = null;
4424 $credits = null;
4425 $description = null;
4426 $hashes = null;
4427 $keywords = null;
4428 $player = null;
4429 $ratings = null;
4430 $restrictions = null;
4431 $thumbnails = null;
4432 $title = null;
4434 // If we have media:group tags, loop through them.
4435 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group)
4437 if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
4439 // If we have media:content tags, loop through them.
4440 foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
4442 if (isset($content['attribs']['']['url']))
4444 // Attributes
4445 $bitrate = null;
4446 $channels = null;
4447 $duration = null;
4448 $expression = null;
4449 $framerate = null;
4450 $height = null;
4451 $javascript = null;
4452 $lang = null;
4453 $length = null;
4454 $medium = null;
4455 $samplingrate = null;
4456 $type = null;
4457 $url = null;
4458 $width = null;
4460 // Elements
4461 $captions = null;
4462 $categories = null;
4463 $copyrights = null;
4464 $credits = null;
4465 $description = null;
4466 $hashes = null;
4467 $keywords = null;
4468 $player = null;
4469 $ratings = null;
4470 $restrictions = null;
4471 $thumbnails = null;
4472 $title = null;
4474 // Start checking the attributes of media:content
4475 if (isset($content['attribs']['']['bitrate']))
4477 $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
4479 if (isset($content['attribs']['']['channels']))
4481 $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
4483 if (isset($content['attribs']['']['duration']))
4485 $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
4487 else
4489 $duration = $duration_parent;
4491 if (isset($content['attribs']['']['expression']))
4493 $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
4495 if (isset($content['attribs']['']['framerate']))
4497 $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
4499 if (isset($content['attribs']['']['height']))
4501 $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
4503 if (isset($content['attribs']['']['lang']))
4505 $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
4507 if (isset($content['attribs']['']['fileSize']))
4509 $length = ceil($content['attribs']['']['fileSize']);
4511 if (isset($content['attribs']['']['medium']))
4513 $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
4515 if (isset($content['attribs']['']['samplingrate']))
4517 $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
4519 if (isset($content['attribs']['']['type']))
4521 $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4523 if (isset($content['attribs']['']['width']))
4525 $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
4527 $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4529 // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
4531 // CAPTIONS
4532 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
4534 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
4536 $caption_type = null;
4537 $caption_lang = null;
4538 $caption_startTime = null;
4539 $caption_endTime = null;
4540 $caption_text = null;
4541 if (isset($caption['attribs']['']['type']))
4543 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4545 if (isset($caption['attribs']['']['lang']))
4547 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
4549 if (isset($caption['attribs']['']['start']))
4551 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
4553 if (isset($caption['attribs']['']['end']))
4555 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
4557 if (isset($caption['data']))
4559 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4561 $captions[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
4563 if (is_array($captions))
4565 $captions = array_values(SimplePie_Misc::array_unique($captions));
4568 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
4570 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
4572 $caption_type = null;
4573 $caption_lang = null;
4574 $caption_startTime = null;
4575 $caption_endTime = null;
4576 $caption_text = null;
4577 if (isset($caption['attribs']['']['type']))
4579 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4581 if (isset($caption['attribs']['']['lang']))
4583 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
4585 if (isset($caption['attribs']['']['start']))
4587 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
4589 if (isset($caption['attribs']['']['end']))
4591 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
4593 if (isset($caption['data']))
4595 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4597 $captions[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
4599 if (is_array($captions))
4601 $captions = array_values(SimplePie_Misc::array_unique($captions));
4604 else
4606 $captions = $captions_parent;
4609 // CATEGORIES
4610 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
4612 foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
4614 $term = null;
4615 $scheme = null;
4616 $label = null;
4617 if (isset($category['data']))
4619 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4621 if (isset($category['attribs']['']['scheme']))
4623 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4625 else
4627 $scheme = 'http://search.yahoo.com/mrss/category_schema';
4629 if (isset($category['attribs']['']['label']))
4631 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
4633 $categories[] = new $this->feed->category_class($term, $scheme, $label);
4636 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
4638 foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
4640 $term = null;
4641 $scheme = null;
4642 $label = null;
4643 if (isset($category['data']))
4645 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4647 if (isset($category['attribs']['']['scheme']))
4649 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4651 else
4653 $scheme = 'http://search.yahoo.com/mrss/category_schema';
4655 if (isset($category['attribs']['']['label']))
4657 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
4659 $categories[] = new $this->feed->category_class($term, $scheme, $label);
4662 if (is_array($categories) && is_array($categories_parent))
4664 $categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent)));
4666 elseif (is_array($categories))
4668 $categories = array_values(SimplePie_Misc::array_unique($categories));
4670 elseif (is_array($categories_parent))
4672 $categories = array_values(SimplePie_Misc::array_unique($categories_parent));
4675 // COPYRIGHTS
4676 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
4678 $copyright_url = null;
4679 $copyright_label = null;
4680 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
4682 $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
4684 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
4686 $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4688 $copyrights = new $this->feed->copyright_class($copyright_url, $copyright_label);
4690 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
4692 $copyright_url = null;
4693 $copyright_label = null;
4694 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
4696 $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
4698 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
4700 $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4702 $copyrights = new $this->feed->copyright_class($copyright_url, $copyright_label);
4704 else
4706 $copyrights = $copyrights_parent;
4709 // CREDITS
4710 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
4712 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
4714 $credit_role = null;
4715 $credit_scheme = null;
4716 $credit_name = null;
4717 if (isset($credit['attribs']['']['role']))
4719 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
4721 if (isset($credit['attribs']['']['scheme']))
4723 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4725 else
4727 $credit_scheme = 'urn:ebu';
4729 if (isset($credit['data']))
4731 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4733 $credits[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
4735 if (is_array($credits))
4737 $credits = array_values(SimplePie_Misc::array_unique($credits));
4740 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
4742 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
4744 $credit_role = null;
4745 $credit_scheme = null;
4746 $credit_name = null;
4747 if (isset($credit['attribs']['']['role']))
4749 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
4751 if (isset($credit['attribs']['']['scheme']))
4753 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4755 else
4757 $credit_scheme = 'urn:ebu';
4759 if (isset($credit['data']))
4761 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4763 $credits[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
4765 if (is_array($credits))
4767 $credits = array_values(SimplePie_Misc::array_unique($credits));
4770 else
4772 $credits = $credits_parent;
4775 // DESCRIPTION
4776 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
4778 $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4780 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
4782 $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4784 else
4786 $description = $description_parent;
4789 // HASHES
4790 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
4792 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
4794 $value = null;
4795 $algo = null;
4796 if (isset($hash['data']))
4798 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4800 if (isset($hash['attribs']['']['algo']))
4802 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
4804 else
4806 $algo = 'md5';
4808 $hashes[] = $algo.':'.$value;
4810 if (is_array($hashes))
4812 $hashes = array_values(SimplePie_Misc::array_unique($hashes));
4815 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
4817 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
4819 $value = null;
4820 $algo = null;
4821 if (isset($hash['data']))
4823 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4825 if (isset($hash['attribs']['']['algo']))
4827 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
4829 else
4831 $algo = 'md5';
4833 $hashes[] = $algo.':'.$value;
4835 if (is_array($hashes))
4837 $hashes = array_values(SimplePie_Misc::array_unique($hashes));
4840 else
4842 $hashes = $hashes_parent;
4845 // KEYWORDS
4846 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
4848 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
4850 $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4851 foreach ($temp as $word)
4853 $keywords[] = trim($word);
4855 unset($temp);
4857 if (is_array($keywords))
4859 $keywords = array_values(SimplePie_Misc::array_unique($keywords));
4862 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
4864 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
4866 $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
4867 foreach ($temp as $word)
4869 $keywords[] = trim($word);
4871 unset($temp);
4873 if (is_array($keywords))
4875 $keywords = array_values(SimplePie_Misc::array_unique($keywords));
4878 else
4880 $keywords = $keywords_parent;
4883 // PLAYER
4884 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
4886 $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4888 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
4890 $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
4892 else
4894 $player = $player_parent;
4897 // RATINGS
4898 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
4900 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
4902 $rating_scheme = null;
4903 $rating_value = null;
4904 if (isset($rating['attribs']['']['scheme']))
4906 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4908 else
4910 $rating_scheme = 'urn:simple';
4912 if (isset($rating['data']))
4914 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4916 $ratings[] = new $this->feed->rating_class($rating_scheme, $rating_value);
4918 if (is_array($ratings))
4920 $ratings = array_values(SimplePie_Misc::array_unique($ratings));
4923 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
4925 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
4927 $rating_scheme = null;
4928 $rating_value = null;
4929 if (isset($rating['attribs']['']['scheme']))
4931 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
4933 else
4935 $rating_scheme = 'urn:simple';
4937 if (isset($rating['data']))
4939 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4941 $ratings[] = new $this->feed->rating_class($rating_scheme, $rating_value);
4943 if (is_array($ratings))
4945 $ratings = array_values(SimplePie_Misc::array_unique($ratings));
4948 else
4950 $ratings = $ratings_parent;
4953 // RESTRICTIONS
4954 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
4956 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
4958 $restriction_relationship = null;
4959 $restriction_type = null;
4960 $restriction_value = null;
4961 if (isset($restriction['attribs']['']['relationship']))
4963 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
4965 if (isset($restriction['attribs']['']['type']))
4967 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4969 if (isset($restriction['data']))
4971 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4973 $restrictions[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
4975 if (is_array($restrictions))
4977 $restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
4980 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
4982 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
4984 $restriction_relationship = null;
4985 $restriction_type = null;
4986 $restriction_value = null;
4987 if (isset($restriction['attribs']['']['relationship']))
4989 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
4991 if (isset($restriction['attribs']['']['type']))
4993 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
4995 if (isset($restriction['data']))
4997 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
4999 $restrictions[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
5001 if (is_array($restrictions))
5003 $restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
5006 else
5008 $restrictions = $restrictions_parent;
5011 // THUMBNAILS
5012 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
5014 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
5016 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
5018 if (is_array($thumbnails))
5020 $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
5023 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
5025 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
5027 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
5029 if (is_array($thumbnails))
5031 $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
5034 else
5036 $thumbnails = $thumbnails_parent;
5039 // TITLES
5040 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
5042 $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5044 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
5046 $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5048 else
5050 $title = $title_parent;
5053 $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width);
5059 // If we have standalone media:content tags, loop through them.
5060 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
5062 foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
5064 if (isset($content['attribs']['']['url']) || isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
5066 // Attributes
5067 $bitrate = null;
5068 $channels = null;
5069 $duration = null;
5070 $expression = null;
5071 $framerate = null;
5072 $height = null;
5073 $javascript = null;
5074 $lang = null;
5075 $length = null;
5076 $medium = null;
5077 $samplingrate = null;
5078 $type = null;
5079 $url = null;
5080 $width = null;
5082 // Elements
5083 $captions = null;
5084 $categories = null;
5085 $copyrights = null;
5086 $credits = null;
5087 $description = null;
5088 $hashes = null;
5089 $keywords = null;
5090 $player = null;
5091 $ratings = null;
5092 $restrictions = null;
5093 $thumbnails = null;
5094 $title = null;
5096 // Start checking the attributes of media:content
5097 if (isset($content['attribs']['']['bitrate']))
5099 $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
5101 if (isset($content['attribs']['']['channels']))
5103 $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
5105 if (isset($content['attribs']['']['duration']))
5107 $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
5109 else
5111 $duration = $duration_parent;
5113 if (isset($content['attribs']['']['expression']))
5115 $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
5117 if (isset($content['attribs']['']['framerate']))
5119 $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
5121 if (isset($content['attribs']['']['height']))
5123 $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
5125 if (isset($content['attribs']['']['lang']))
5127 $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
5129 if (isset($content['attribs']['']['fileSize']))
5131 $length = ceil($content['attribs']['']['fileSize']);
5133 if (isset($content['attribs']['']['medium']))
5135 $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
5137 if (isset($content['attribs']['']['samplingrate']))
5139 $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
5141 if (isset($content['attribs']['']['type']))
5143 $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
5145 if (isset($content['attribs']['']['width']))
5147 $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
5149 if (isset($content['attribs']['']['url']))
5151 $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
5153 // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
5155 // CAPTIONS
5156 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
5158 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
5160 $caption_type = null;
5161 $caption_lang = null;
5162 $caption_startTime = null;
5163 $caption_endTime = null;
5164 $caption_text = null;
5165 if (isset($caption['attribs']['']['type']))
5167 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
5169 if (isset($caption['attribs']['']['lang']))
5171 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
5173 if (isset($caption['attribs']['']['start']))
5175 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
5177 if (isset($caption['attribs']['']['end']))
5179 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
5181 if (isset($caption['data']))
5183 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5185 $captions[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
5187 if (is_array($captions))
5189 $captions = array_values(SimplePie_Misc::array_unique($captions));
5192 else
5194 $captions = $captions_parent;
5197 // CATEGORIES
5198 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
5200 foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
5202 $term = null;
5203 $scheme = null;
5204 $label = null;
5205 if (isset($category['data']))
5207 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5209 if (isset($category['attribs']['']['scheme']))
5211 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
5213 else
5215 $scheme = 'http://search.yahoo.com/mrss/category_schema';
5217 if (isset($category['attribs']['']['label']))
5219 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
5221 $categories[] = new $this->feed->category_class($term, $scheme, $label);
5224 if (is_array($categories) && is_array($categories_parent))
5226 $categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent)));
5228 elseif (is_array($categories))
5230 $categories = array_values(SimplePie_Misc::array_unique($categories));
5232 elseif (is_array($categories_parent))
5234 $categories = array_values(SimplePie_Misc::array_unique($categories_parent));
5236 else
5238 $categories = null;
5241 // COPYRIGHTS
5242 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
5244 $copyright_url = null;
5245 $copyright_label = null;
5246 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
5248 $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
5250 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
5252 $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5254 $copyrights = new $this->feed->copyright_class($copyright_url, $copyright_label);
5256 else
5258 $copyrights = $copyrights_parent;
5261 // CREDITS
5262 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
5264 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
5266 $credit_role = null;
5267 $credit_scheme = null;
5268 $credit_name = null;
5269 if (isset($credit['attribs']['']['role']))
5271 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
5273 if (isset($credit['attribs']['']['scheme']))
5275 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
5277 else
5279 $credit_scheme = 'urn:ebu';
5281 if (isset($credit['data']))
5283 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5285 $credits[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
5287 if (is_array($credits))
5289 $credits = array_values(SimplePie_Misc::array_unique($credits));
5292 else
5294 $credits = $credits_parent;
5297 // DESCRIPTION
5298 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
5300 $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5302 else
5304 $description = $description_parent;
5307 // HASHES
5308 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
5310 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
5312 $value = null;
5313 $algo = null;
5314 if (isset($hash['data']))
5316 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5318 if (isset($hash['attribs']['']['algo']))
5320 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
5322 else
5324 $algo = 'md5';
5326 $hashes[] = $algo.':'.$value;
5328 if (is_array($hashes))
5330 $hashes = array_values(SimplePie_Misc::array_unique($hashes));
5333 else
5335 $hashes = $hashes_parent;
5338 // KEYWORDS
5339 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
5341 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
5343 $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
5344 foreach ($temp as $word)
5346 $keywords[] = trim($word);
5348 unset($temp);
5350 if (is_array($keywords))
5352 $keywords = array_values(SimplePie_Misc::array_unique($keywords));
5355 else
5357 $keywords = $keywords_parent;
5360 // PLAYER
5361 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
5363 $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
5365 else
5367 $player = $player_parent;
5370 // RATINGS
5371 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
5373 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
5375 $rating_scheme = null;
5376 $rating_value = null;
5377 if (isset($rating['attribs']['']['scheme']))
5379 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
5381 else
5383 $rating_scheme = 'urn:simple';
5385 if (isset($rating['data']))
5387 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5389 $ratings[] = new $this->feed->rating_class($rating_scheme, $rating_value);
5391 if (is_array($ratings))
5393 $ratings = array_values(SimplePie_Misc::array_unique($ratings));
5396 else
5398 $ratings = $ratings_parent;
5401 // RESTRICTIONS
5402 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
5404 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
5406 $restriction_relationship = null;
5407 $restriction_type = null;
5408 $restriction_value = null;
5409 if (isset($restriction['attribs']['']['relationship']))
5411 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
5413 if (isset($restriction['attribs']['']['type']))
5415 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
5417 if (isset($restriction['data']))
5419 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5421 $restrictions[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
5423 if (is_array($restrictions))
5425 $restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
5428 else
5430 $restrictions = $restrictions_parent;
5433 // THUMBNAILS
5434 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
5436 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
5438 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
5440 if (is_array($thumbnails))
5442 $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
5445 else
5447 $thumbnails = $thumbnails_parent;
5450 // TITLES
5451 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
5453 $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5455 else
5457 $title = $title_parent;
5460 $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width);
5465 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
5467 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
5469 // Attributes
5470 $bitrate = null;
5471 $channels = null;
5472 $duration = null;
5473 $expression = null;
5474 $framerate = null;
5475 $height = null;
5476 $javascript = null;
5477 $lang = null;
5478 $length = null;
5479 $medium = null;
5480 $samplingrate = null;
5481 $type = null;
5482 $url = null;
5483 $width = null;
5485 $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
5486 if (isset($link['attribs']['']['type']))
5488 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
5490 if (isset($link['attribs']['']['length']))
5492 $length = ceil($link['attribs']['']['length']);
5495 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
5496 $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $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);
5500 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
5502 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
5504 // Attributes
5505 $bitrate = null;
5506 $channels = null;
5507 $duration = null;
5508 $expression = null;
5509 $framerate = null;
5510 $height = null;
5511 $javascript = null;
5512 $lang = null;
5513 $length = null;
5514 $medium = null;
5515 $samplingrate = null;
5516 $type = null;
5517 $url = null;
5518 $width = null;
5520 $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
5521 if (isset($link['attribs']['']['type']))
5523 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
5525 if (isset($link['attribs']['']['length']))
5527 $length = ceil($link['attribs']['']['length']);
5530 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
5531 $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $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);
5535 if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure'))
5537 if (isset($enclosure[0]['attribs']['']['url']))
5539 // Attributes
5540 $bitrate = null;
5541 $channels = null;
5542 $duration = null;
5543 $expression = null;
5544 $framerate = null;
5545 $height = null;
5546 $javascript = null;
5547 $lang = null;
5548 $length = null;
5549 $medium = null;
5550 $samplingrate = null;
5551 $type = null;
5552 $url = null;
5553 $width = null;
5555 $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
5556 if (isset($enclosure[0]['attribs']['']['type']))
5558 $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
5560 if (isset($enclosure[0]['attribs']['']['length']))
5562 $length = ceil($enclosure[0]['attribs']['']['length']);
5565 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
5566 $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $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);
5570 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))
5572 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
5573 $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $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);
5576 $this->data['enclosures'] = array_values(SimplePie_Misc::array_unique($this->data['enclosures']));
5578 if (!empty($this->data['enclosures']))
5580 return $this->data['enclosures'];
5582 else
5584 return null;
5588 function get_latitude()
5590 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
5592 return (float) $return[0]['data'];
5594 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))
5596 return (float) $match[1];
5598 else
5600 return null;
5604 function get_longitude()
5606 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
5608 return (float) $return[0]['data'];
5610 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
5612 return (float) $return[0]['data'];
5614 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))
5616 return (float) $match[2];
5618 else
5620 return null;
5624 function get_source()
5626 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
5628 return new $this->feed->source_class($this, $return[0]);
5630 else
5632 return null;
5637 * Creates the add_to_* methods' return data
5639 * @access private
5640 * @param string $item_url String to prefix to the item permalink
5641 * @param string $title_url String to prefix to the item title
5642 * (and suffix to the item permalink)
5643 * @return mixed URL if feed exists, false otherwise
5645 function add_to_service($item_url, $title_url = null, $summary_url = null)
5647 if ($this->get_permalink() !== null)
5649 $return = $item_url . rawurlencode($this->get_permalink());
5650 if ($title_url !== null && $this->get_title() !== null)
5652 $return .= $title_url . rawurlencode($this->get_title());
5654 if ($summary_url !== null && $this->get_description() !== null)
5656 $return .= $summary_url . rawurlencode($this->get_description());
5658 return $this->sanitize($return, SIMPLEPIE_CONSTRUCT_IRI);
5660 else
5662 return null;
5666 function add_to_blinklist()
5668 return $this->add_to_service('http://www.blinklist.com/index.php?Action=Blink/addblink.php&Description=&Url=', '&Title=');
5671 function add_to_blogmarks()
5673 return $this->add_to_service('http://blogmarks.net/my/new.php?mini=1&simple=1&url=', '&title=');
5676 function add_to_delicious()
5678 return $this->add_to_service('http://del.icio.us/post/?v=4&url=', '&title=');
5681 function add_to_digg()
5683 return $this->add_to_service('http://digg.com/submit?url=', '&title=', '&bodytext=');
5686 function add_to_furl()
5688 return $this->add_to_service('http://www.furl.net/storeIt.jsp?u=', '&t=');
5691 function add_to_magnolia()
5693 return $this->add_to_service('http://ma.gnolia.com/bookmarklet/add?url=', '&title=');
5696 function add_to_myweb20()
5698 return $this->add_to_service('http://myweb2.search.yahoo.com/myresults/bookmarklet?u=', '&t=');
5701 function add_to_newsvine()
5703 return $this->add_to_service('http://www.newsvine.com/_wine/save?u=', '&h=');
5706 function add_to_reddit()
5708 return $this->add_to_service('http://reddit.com/submit?url=', '&title=');
5711 function add_to_segnalo()
5713 return $this->add_to_service('http://segnalo.com/post.html.php?url=', '&title=');
5716 function add_to_simpy()
5718 return $this->add_to_service('http://www.simpy.com/simpy/LinkAdd.do?href=', '&title=');
5721 function add_to_spurl()
5723 return $this->add_to_service('http://www.spurl.net/spurl.php?v=3&url=', '&title=');
5726 function add_to_wists()
5728 return $this->add_to_service('http://wists.com/r.php?c=&r=', '&title=');
5731 function search_technorati()
5733 return $this->add_to_service('http://www.technorati.com/search/');
5737 class SimplePie_Source
5739 var $item;
5740 var $data = array();
5742 function SimplePie_Source($item, $data)
5744 $this->item = $item;
5745 $this->data = $data;
5748 function __toString()
5750 return md5(serialize($this->data));
5753 function get_source_tags($namespace, $tag)
5755 if (isset($this->data['child'][$namespace][$tag]))
5757 return $this->data['child'][$namespace][$tag];
5759 else
5761 return null;
5765 function get_base($element = array())
5767 return $this->item->get_base($element);
5770 function sanitize($data, $type, $base = '')
5772 return $this->item->sanitize($data, $type, $base);
5775 function get_item()
5777 return $this->item;
5780 function get_title()
5782 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
5784 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
5786 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
5788 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
5790 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
5792 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
5794 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
5796 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
5798 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
5800 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
5802 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
5804 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5806 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
5808 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5810 else
5812 return null;
5816 function get_category($key = 0)
5818 $categories = $this->get_categories();
5819 if (isset($categories[$key]))
5821 return $categories[$key];
5823 else
5825 return null;
5829 function get_categories()
5831 $categories = array();
5833 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
5835 $term = null;
5836 $scheme = null;
5837 $label = null;
5838 if (isset($category['attribs']['']['term']))
5840 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
5842 if (isset($category['attribs']['']['scheme']))
5844 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
5846 if (isset($category['attribs']['']['label']))
5848 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
5850 $categories[] = new $this->item->feed->category_class($term, $scheme, $label);
5852 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
5854 // This is really the label, but keep this as the term also for BC.
5855 // Label will also work on retrieving because that falls back to term.
5856 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5857 if (isset($category['attribs']['']['domain']))
5859 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
5861 else
5863 $scheme = null;
5865 $categories[] = new $this->item->feed->category_class($term, $scheme, null);
5867 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
5869 $categories[] = new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
5871 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
5873 $categories[] = new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
5876 if (!empty($categories))
5878 return SimplePie_Misc::array_unique($categories);
5880 else
5882 return null;
5886 function get_author($key = 0)
5888 $authors = $this->get_authors();
5889 if (isset($authors[$key]))
5891 return $authors[$key];
5893 else
5895 return null;
5899 function get_authors()
5901 $authors = array();
5902 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
5904 $name = null;
5905 $uri = null;
5906 $email = null;
5907 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
5909 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5911 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
5913 $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]));
5915 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
5917 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5919 if ($name !== null || $email !== null || $uri !== null)
5921 $authors[] = new $this->item->feed->author_class($name, $uri, $email);
5924 if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
5926 $name = null;
5927 $url = null;
5928 $email = null;
5929 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
5931 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5933 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
5935 $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]));
5937 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
5939 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5941 if ($name !== null || $email !== null || $url !== null)
5943 $authors[] = new $this->item->feed->author_class($name, $url, $email);
5946 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
5948 $authors[] = new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
5950 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
5952 $authors[] = new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
5954 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
5956 $authors[] = new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
5959 if (!empty($authors))
5961 return SimplePie_Misc::array_unique($authors);
5963 else
5965 return null;
5969 function get_contributor($key = 0)
5971 $contributors = $this->get_contributors();
5972 if (isset($contributors[$key]))
5974 return $contributors[$key];
5976 else
5978 return null;
5982 function get_contributors()
5984 $contributors = array();
5985 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
5987 $name = null;
5988 $uri = null;
5989 $email = null;
5990 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
5992 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
5994 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
5996 $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]));
5998 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
6000 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6002 if ($name !== null || $email !== null || $uri !== null)
6004 $contributors[] = new $this->item->feed->author_class($name, $uri, $email);
6007 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
6009 $name = null;
6010 $url = null;
6011 $email = null;
6012 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
6014 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6016 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
6018 $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]));
6020 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
6022 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6024 if ($name !== null || $email !== null || $url !== null)
6026 $contributors[] = new $this->item->feed->author_class($name, $url, $email);
6030 if (!empty($contributors))
6032 return SimplePie_Misc::array_unique($contributors);
6034 else
6036 return null;
6040 function get_link($key = 0, $rel = 'alternate')
6042 $links = $this->get_links($rel);
6043 if (isset($links[$key]))
6045 return $links[$key];
6047 else
6049 return null;
6054 * Added for parity between the parent-level and the item/entry-level.
6056 function get_permalink()
6058 return $this->get_link(0);
6061 function get_links($rel = 'alternate')
6063 if (!isset($this->data['links']))
6065 $this->data['links'] = array();
6066 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
6068 foreach ($links as $link)
6070 if (isset($link['attribs']['']['href']))
6072 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
6073 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
6077 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
6079 foreach ($links as $link)
6081 if (isset($link['attribs']['']['href']))
6083 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
6084 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
6089 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
6091 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
6093 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
6095 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
6097 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
6099 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
6102 $keys = array_keys($this->data['links']);
6103 foreach ($keys as $key)
6105 if (SimplePie_Misc::is_isegment_nz_nc($key))
6107 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
6109 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
6110 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
6112 else
6114 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
6117 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
6119 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
6121 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
6125 if (isset($this->data['links'][$rel]))
6127 return $this->data['links'][$rel];
6129 else
6131 return null;
6135 function get_description()
6137 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
6139 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
6141 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
6143 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
6145 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
6147 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
6149 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
6151 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
6153 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
6155 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
6157 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
6159 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6161 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
6163 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6165 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
6167 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
6169 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
6171 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
6173 else
6175 return null;
6179 function get_copyright()
6181 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
6183 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
6185 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
6187 return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
6189 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
6191 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6193 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
6195 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6197 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
6199 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6201 else
6203 return null;
6207 function get_language()
6209 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
6211 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6213 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
6215 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6217 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
6219 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
6221 elseif (isset($this->data['xml_lang']))
6223 return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
6225 else
6227 return null;
6231 function get_latitude()
6233 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
6235 return (float) $return[0]['data'];
6237 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))
6239 return (float) $match[1];
6241 else
6243 return null;
6247 function get_longitude()
6249 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
6251 return (float) $return[0]['data'];
6253 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
6255 return (float) $return[0]['data'];
6257 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))
6259 return (float) $match[2];
6261 else
6263 return null;
6267 function get_image_url()
6269 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
6271 return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
6273 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
6275 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
6277 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
6279 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
6281 else
6283 return null;
6288 class SimplePie_Author
6290 var $name;
6291 var $link;
6292 var $email;
6294 // Constructor, used to input the data
6295 function SimplePie_Author($name = null, $link = null, $email = null)
6297 $this->name = $name;
6298 $this->link = $link;
6299 $this->email = $email;
6302 function __toString()
6304 // There is no $this->data here
6305 return md5(serialize($this));
6308 function get_name()
6310 if ($this->name !== null)
6312 return $this->name;
6314 else
6316 return null;
6320 function get_link()
6322 if ($this->link !== null)
6324 return $this->link;
6326 else
6328 return null;
6332 function get_email()
6334 if ($this->email !== null)
6336 return $this->email;
6338 else
6340 return null;
6345 class SimplePie_Category
6347 var $term;
6348 var $scheme;
6349 var $label;
6351 // Constructor, used to input the data
6352 function SimplePie_Category($term = null, $scheme = null, $label = null)
6354 $this->term = $term;
6355 $this->scheme = $scheme;
6356 $this->label = $label;
6359 function __toString()
6361 // There is no $this->data here
6362 return md5(serialize($this));
6365 function get_term()
6367 if ($this->term !== null)
6369 return $this->term;
6371 else
6373 return null;
6377 function get_scheme()
6379 if ($this->scheme !== null)
6381 return $this->scheme;
6383 else
6385 return null;
6389 function get_label()
6391 if ($this->label !== null)
6393 return $this->label;
6395 else
6397 return $this->get_term();
6402 class SimplePie_Enclosure
6404 var $bitrate;
6405 var $captions;
6406 var $categories;
6407 var $channels;
6408 var $copyright;
6409 var $credits;
6410 var $description;
6411 var $duration;
6412 var $expression;
6413 var $framerate;
6414 var $handler;
6415 var $hashes;
6416 var $height;
6417 var $javascript;
6418 var $keywords;
6419 var $lang;
6420 var $length;
6421 var $link;
6422 var $medium;
6423 var $player;
6424 var $ratings;
6425 var $restrictions;
6426 var $samplingrate;
6427 var $thumbnails;
6428 var $title;
6429 var $type;
6430 var $width;
6432 // Constructor, used to input the data
6433 function SimplePie_Enclosure($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)
6435 $this->bitrate = $bitrate;
6436 $this->captions = $captions;
6437 $this->categories = $categories;
6438 $this->channels = $channels;
6439 $this->copyright = $copyright;
6440 $this->credits = $credits;
6441 $this->description = $description;
6442 $this->duration = $duration;
6443 $this->expression = $expression;
6444 $this->framerate = $framerate;
6445 $this->hashes = $hashes;
6446 $this->height = $height;
6447 $this->javascript = $javascript;
6448 $this->keywords = $keywords;
6449 $this->lang = $lang;
6450 $this->length = $length;
6451 $this->link = $link;
6452 $this->medium = $medium;
6453 $this->player = $player;
6454 $this->ratings = $ratings;
6455 $this->restrictions = $restrictions;
6456 $this->samplingrate = $samplingrate;
6457 $this->thumbnails = $thumbnails;
6458 $this->title = $title;
6459 $this->type = $type;
6460 $this->width = $width;
6461 if (class_exists('idna_convert'))
6463 $idn = new idna_convert;
6464 $parsed = SimplePie_Misc::parse_url($link);
6465 $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
6467 $this->handler = $this->get_handler(); // Needs to load last
6470 function __toString()
6472 // There is no $this->data here
6473 return md5(serialize($this));
6476 function get_bitrate()
6478 if ($this->bitrate !== null)
6480 return $this->bitrate;
6482 else
6484 return null;
6488 function get_caption($key = 0)
6490 $captions = $this->get_captions();
6491 if (isset($captions[$key]))
6493 return $captions[$key];
6495 else
6497 return null;
6501 function get_captions()
6503 if ($this->captions !== null)
6505 return $this->captions;
6507 else
6509 return null;
6513 function get_category($key = 0)
6515 $categories = $this->get_categories();
6516 if (isset($categories[$key]))
6518 return $categories[$key];
6520 else
6522 return null;
6526 function get_categories()
6528 if ($this->categories !== null)
6530 return $this->categories;
6532 else
6534 return null;
6538 function get_channels()
6540 if ($this->channels !== null)
6542 return $this->channels;
6544 else
6546 return null;
6550 function get_copyright()
6552 if ($this->copyright !== null)
6554 return $this->copyright;
6556 else
6558 return null;
6562 function get_credit($key = 0)
6564 $credits = $this->get_credits();
6565 if (isset($credits[$key]))
6567 return $credits[$key];
6569 else
6571 return null;
6575 function get_credits()
6577 if ($this->credits !== null)
6579 return $this->credits;
6581 else
6583 return null;
6587 function get_description()
6589 if ($this->description !== null)
6591 return $this->description;
6593 else
6595 return null;
6599 function get_duration($convert = false)
6601 if ($this->duration !== null)
6603 if ($convert)
6605 $time = SimplePie_Misc::time_hms($this->duration);
6606 return $time;
6608 else
6610 return $this->duration;
6613 else
6615 return null;
6619 function get_expression()
6621 if ($this->expression !== null)
6623 return $this->expression;
6625 else
6627 return 'full';
6631 function get_extension()
6633 if ($this->link !== null)
6635 $url = SimplePie_Misc::parse_url($this->link);
6636 if ($url['path'] !== '')
6638 return pathinfo($url['path'], PATHINFO_EXTENSION);
6641 return null;
6644 function get_framerate()
6646 if ($this->framerate !== null)
6648 return $this->framerate;
6650 else
6652 return null;
6656 function get_handler()
6658 return $this->get_real_type(true);
6661 function get_hash($key = 0)
6663 $hashes = $this->get_hashes();
6664 if (isset($hashes[$key]))
6666 return $hashes[$key];
6668 else
6670 return null;
6674 function get_hashes()
6676 if ($this->hashes !== null)
6678 return $this->hashes;
6680 else
6682 return null;
6686 function get_height()
6688 if ($this->height !== null)
6690 return $this->height;
6692 else
6694 return null;
6698 function get_language()
6700 if ($this->lang !== null)
6702 return $this->lang;
6704 else
6706 return null;
6710 function get_keyword($key = 0)
6712 $keywords = $this->get_keywords();
6713 if (isset($keywords[$key]))
6715 return $keywords[$key];
6717 else
6719 return null;
6723 function get_keywords()
6725 if ($this->keywords !== null)
6727 return $this->keywords;
6729 else
6731 return null;
6735 function get_length()
6737 if ($this->length !== null)
6739 return $this->length;
6741 else
6743 return null;
6747 function get_link()
6749 if ($this->link !== null)
6751 return urldecode($this->link);
6753 else
6755 return null;
6759 function get_medium()
6761 if ($this->medium !== null)
6763 return $this->medium;
6765 else
6767 return null;
6771 function get_player()
6773 if ($this->player !== null)
6775 return $this->player;
6777 else
6779 return null;
6783 function get_rating($key = 0)
6785 $ratings = $this->get_ratings();
6786 if (isset($ratings[$key]))
6788 return $ratings[$key];
6790 else
6792 return null;
6796 function get_ratings()
6798 if ($this->ratings !== null)
6800 return $this->ratings;
6802 else
6804 return null;
6808 function get_restriction($key = 0)
6810 $restrictions = $this->get_restrictions();
6811 if (isset($restrictions[$key]))
6813 return $restrictions[$key];
6815 else
6817 return null;
6821 function get_restrictions()
6823 if ($this->restrictions !== null)
6825 return $this->restrictions;
6827 else
6829 return null;
6833 function get_sampling_rate()
6835 if ($this->samplingrate !== null)
6837 return $this->samplingrate;
6839 else
6841 return null;
6845 function get_size()
6847 $length = $this->get_length();
6848 if ($length !== null)
6850 return round($length/1048576, 2);
6852 else
6854 return null;
6858 function get_thumbnail($key = 0)
6860 $thumbnails = $this->get_thumbnails();
6861 if (isset($thumbnails[$key]))
6863 return $thumbnails[$key];
6865 else
6867 return null;
6871 function get_thumbnails()
6873 if ($this->thumbnails !== null)
6875 return $this->thumbnails;
6877 else
6879 return null;
6883 function get_title()
6885 if ($this->title !== null)
6887 return $this->title;
6889 else
6891 return null;
6895 function get_type()
6897 if ($this->type !== null)
6899 return $this->type;
6901 else
6903 return null;
6907 function get_width()
6909 if ($this->width !== null)
6911 return $this->width;
6913 else
6915 return null;
6919 function native_embed($options='')
6921 return $this->embed($options, true);
6925 * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
6927 function embed($options = '', $native = false)
6929 // Set up defaults
6930 $audio = '';
6931 $video = '';
6932 $alt = '';
6933 $altclass = '';
6934 $loop = 'false';
6935 $width = 'auto';
6936 $height = 'auto';
6937 $bgcolor = '#ffffff';
6938 $mediaplayer = '';
6939 $widescreen = false;
6940 $handler = $this->get_handler();
6941 $type = $this->get_real_type();
6943 // Process options and reassign values as necessary
6944 if (is_array($options))
6946 extract($options);
6948 else
6950 $options = explode(',', $options);
6951 foreach($options as $option)
6953 $opt = explode(':', $option, 2);
6954 if (isset($opt[0], $opt[1]))
6956 $opt[0] = trim($opt[0]);
6957 $opt[1] = trim($opt[1]);
6958 switch ($opt[0])
6960 case 'audio':
6961 $audio = $opt[1];
6962 break;
6964 case 'video':
6965 $video = $opt[1];
6966 break;
6968 case 'alt':
6969 $alt = $opt[1];
6970 break;
6972 case 'altclass':
6973 $altclass = $opt[1];
6974 break;
6976 case 'loop':
6977 $loop = $opt[1];
6978 break;
6980 case 'width':
6981 $width = $opt[1];
6982 break;
6984 case 'height':
6985 $height = $opt[1];
6986 break;
6988 case 'bgcolor':
6989 $bgcolor = $opt[1];
6990 break;
6992 case 'mediaplayer':
6993 $mediaplayer = $opt[1];
6994 break;
6996 case 'widescreen':
6997 $widescreen = $opt[1];
6998 break;
7004 $mime = explode('/', $type, 2);
7005 $mime = $mime[0];
7007 // Process values for 'auto'
7008 if ($width === 'auto')
7010 if ($mime === 'video')
7012 if ($height === 'auto')
7014 $width = 480;
7016 elseif ($widescreen)
7018 $width = round((intval($height)/9)*16);
7020 else
7022 $width = round((intval($height)/3)*4);
7025 else
7027 $width = '100%';
7031 if ($height === 'auto')
7033 if ($mime === 'audio')
7035 $height = 0;
7037 elseif ($mime === 'video')
7039 if ($width === 'auto')
7041 if ($widescreen)
7043 $height = 270;
7045 else
7047 $height = 360;
7050 elseif ($widescreen)
7052 $height = round((intval($width)/16)*9);
7054 else
7056 $height = round((intval($width)/4)*3);
7059 else
7061 $height = 376;
7064 elseif ($mime === 'audio')
7066 $height = 0;
7069 // Set proper placeholder value
7070 if ($mime === 'audio')
7072 $placeholder = $audio;
7074 elseif ($mime === 'video')
7076 $placeholder = $video;
7079 $embed = '';
7081 // Make sure the JS library is included
7082 if (!$native)
7084 static $javascript_outputted = null;
7085 if (!$javascript_outputted && $this->javascript)
7087 $embed .= '<script type="text/javascript" src="?' . htmlspecialchars($this->javascript) . '"></script>';
7088 $javascript_outputted = true;
7092 // Odeo Feed MP3's
7093 if ($handler === 'odeo')
7095 if ($native)
7097 $embed .= '<embed src="http://odeo.com/flash/audio_player_fullsize.swf" pluginspage="http://adobe.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="440" height="80" wmode="transparent" allowScriptAccess="any" flashvars="valid_sample_rate=true&external_url=' . $this->get_link() . '"></embed>';
7099 else
7101 $embed .= '<script type="text/javascript">embed_odeo("' . $this->get_link() . '");</script>';
7105 // Flash
7106 elseif ($handler === 'flash')
7108 if ($native)
7110 $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>";
7112 else
7114 $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
7118 // Flash Media Player file types.
7119 // Preferred handler for MP3 file types.
7120 elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
7122 $height += 20;
7123 if ($native)
7125 $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>";
7127 else
7129 $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
7133 // QuickTime 7 file types. Need to test with QuickTime 6.
7134 // Only handle MP3's if the Flash Media Player is not present.
7135 elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === ''))
7137 $height += 16;
7138 if ($native)
7140 if ($placeholder !== '')
7142 $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>";
7144 else
7146 $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>";
7149 else
7151 $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
7155 // Windows Media
7156 elseif ($handler === 'wmedia')
7158 $height += 45;
7159 if ($native)
7161 $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>";
7163 else
7165 $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
7169 // Everything else
7170 else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
7172 return $embed;
7175 function get_real_type($find_handler = false)
7177 // If it's Odeo, let's get it out of the way.
7178 if (substr(strtolower($this->get_link()), 0, 15) === 'http://odeo.com')
7180 return 'odeo';
7183 // Mime-types by handler.
7184 $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
7185 $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
7186 $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
7187 $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
7188 $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
7190 if ($this->get_type() !== null)
7192 $type = strtolower($this->type);
7194 else
7196 $type = null;
7199 // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
7200 if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
7202 switch (strtolower($this->get_extension()))
7204 // Audio mime-types
7205 case 'aac':
7206 case 'adts':
7207 $type = 'audio/acc';
7208 break;
7210 case 'aif':
7211 case 'aifc':
7212 case 'aiff':
7213 case 'cdda':
7214 $type = 'audio/aiff';
7215 break;
7217 case 'bwf':
7218 $type = 'audio/wav';
7219 break;
7221 case 'kar':
7222 case 'mid':
7223 case 'midi':
7224 case 'smf':
7225 $type = 'audio/midi';
7226 break;
7228 case 'm4a':
7229 $type = 'audio/x-m4a';
7230 break;
7232 case 'mp3':
7233 case 'swa':
7234 $type = 'audio/mp3';
7235 break;
7237 case 'wav':
7238 $type = 'audio/wav';
7239 break;
7241 case 'wax':
7242 $type = 'audio/x-ms-wax';
7243 break;
7245 case 'wma':
7246 $type = 'audio/x-ms-wma';
7247 break;
7249 // Video mime-types
7250 case '3gp':
7251 case '3gpp':
7252 $type = 'video/3gpp';
7253 break;
7255 case '3g2':
7256 case '3gp2':
7257 $type = 'video/3gpp2';
7258 break;
7260 case 'asf':
7261 $type = 'video/x-ms-asf';
7262 break;
7264 case 'flv':
7265 $type = 'video/x-flv';
7266 break;
7268 case 'm1a':
7269 case 'm1s':
7270 case 'm1v':
7271 case 'm15':
7272 case 'm75':
7273 case 'mp2':
7274 case 'mpa':
7275 case 'mpeg':
7276 case 'mpg':
7277 case 'mpm':
7278 case 'mpv':
7279 $type = 'video/mpeg';
7280 break;
7282 case 'm4v':
7283 $type = 'video/x-m4v';
7284 break;
7286 case 'mov':
7287 case 'qt':
7288 $type = 'video/quicktime';
7289 break;
7291 case 'mp4':
7292 case 'mpg4':
7293 $type = 'video/mp4';
7294 break;
7296 case 'sdv':
7297 $type = 'video/sd-video';
7298 break;
7300 case 'wm':
7301 $type = 'video/x-ms-wm';
7302 break;
7304 case 'wmv':
7305 $type = 'video/x-ms-wmv';
7306 break;
7308 case 'wvx':
7309 $type = 'video/x-ms-wvx';
7310 break;
7312 // Flash mime-types
7313 case 'spl':
7314 $type = 'application/futuresplash';
7315 break;
7317 case 'swf':
7318 $type = 'application/x-shockwave-flash';
7319 break;
7323 if ($find_handler)
7325 if (in_array($type, $types_flash))
7327 return 'flash';
7329 elseif (in_array($type, $types_fmedia))
7331 return 'fmedia';
7333 elseif (in_array($type, $types_quicktime))
7335 return 'quicktime';
7337 elseif (in_array($type, $types_wmedia))
7339 return 'wmedia';
7341 elseif (in_array($type, $types_mp3))
7343 return 'mp3';
7345 else
7347 return null;
7350 else
7352 return $type;
7357 class SimplePie_Caption
7359 var $type;
7360 var $lang;
7361 var $startTime;
7362 var $endTime;
7363 var $text;
7365 // Constructor, used to input the data
7366 function SimplePie_Caption($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
7368 $this->type = $type;
7369 $this->lang = $lang;
7370 $this->startTime = $startTime;
7371 $this->endTime = $endTime;
7372 $this->text = $text;
7375 function __toString()
7377 // There is no $this->data here
7378 return md5(serialize($this));
7381 function get_endtime()
7383 if ($this->endTime !== null)
7385 return $this->endTime;
7387 else
7389 return null;
7393 function get_language()
7395 if ($this->lang !== null)
7397 return $this->lang;
7399 else
7401 return null;
7405 function get_starttime()
7407 if ($this->startTime !== null)
7409 return $this->startTime;
7411 else
7413 return null;
7417 function get_text()
7419 if ($this->text !== null)
7421 return $this->text;
7423 else
7425 return null;
7429 function get_type()
7431 if ($this->type !== null)
7433 return $this->type;
7435 else
7437 return null;
7442 class SimplePie_Credit
7444 var $role;
7445 var $scheme;
7446 var $name;
7448 // Constructor, used to input the data
7449 function SimplePie_Credit($role = null, $scheme = null, $name = null)
7451 $this->role = $role;
7452 $this->scheme = $scheme;
7453 $this->name = $name;
7456 function __toString()
7458 // There is no $this->data here
7459 return md5(serialize($this));
7462 function get_role()
7464 if ($this->role !== null)
7466 return $this->role;
7468 else
7470 return null;
7474 function get_scheme()
7476 if ($this->scheme !== null)
7478 return $this->scheme;
7480 else
7482 return null;
7486 function get_name()
7488 if ($this->name !== null)
7490 return $this->name;
7492 else
7494 return null;
7499 class SimplePie_Copyright
7501 var $url;
7502 var $label;
7504 // Constructor, used to input the data
7505 function SimplePie_Copyright($url = null, $label = null)
7507 $this->url = $url;
7508 $this->label = $label;
7511 function __toString()
7513 // There is no $this->data here
7514 return md5(serialize($this));
7517 function get_url()
7519 if ($this->url !== null)
7521 return $this->url;
7523 else
7525 return null;
7529 function get_attribution()
7531 if ($this->label !== null)
7533 return $this->label;
7535 else
7537 return null;
7542 class SimplePie_Rating
7544 var $scheme;
7545 var $value;
7547 // Constructor, used to input the data
7548 function SimplePie_Rating($scheme = null, $value = null)
7550 $this->scheme = $scheme;
7551 $this->value = $value;
7554 function __toString()
7556 // There is no $this->data here
7557 return md5(serialize($this));
7560 function get_scheme()
7562 if ($this->scheme !== null)
7564 return $this->scheme;
7566 else
7568 return null;
7572 function get_value()
7574 if ($this->value !== null)
7576 return $this->value;
7578 else
7580 return null;
7585 class SimplePie_Restriction
7587 var $relationship;
7588 var $type;
7589 var $value;
7591 // Constructor, used to input the data
7592 function SimplePie_Restriction($relationship = null, $type = null, $value = null)
7594 $this->relationship = $relationship;
7595 $this->type = $type;
7596 $this->value = $value;
7599 function __toString()
7601 // There is no $this->data here
7602 return md5(serialize($this));
7605 function get_relationship()
7607 if ($this->relationship !== null)
7609 return $this->relationship;
7611 else
7613 return null;
7617 function get_type()
7619 if ($this->type !== null)
7621 return $this->type;
7623 else
7625 return null;
7629 function get_value()
7631 if ($this->value !== null)
7633 return $this->value;
7635 else
7637 return null;
7643 * @todo Move to properly supporting RFC2616 (HTTP/1.1)
7645 class SimplePie_File
7647 var $url;
7648 var $useragent;
7649 var $success = true;
7650 var $headers = array();
7651 var $body;
7652 var $status_code;
7653 var $redirects = 0;
7654 var $error;
7655 var $method = SIMPLEPIE_FILE_SOURCE_NONE;
7657 function SimplePie_File($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
7659 if (class_exists('idna_convert'))
7661 $idn = new idna_convert;
7662 $parsed = SimplePie_Misc::parse_url($url);
7663 $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
7665 $this->url = $url;
7666 $this->useragent = $useragent;
7667 if (preg_match('/^http(s)?:\/\//i', $url))
7669 if ($useragent === null)
7671 $useragent = ini_get('user_agent');
7672 $this->useragent = $useragent;
7674 if (!is_array($headers))
7676 $headers = array();
7678 if (!$force_fsockopen && function_exists('curl_exec'))
7680 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
7681 $fp = curl_init();
7682 $headers2 = array();
7683 foreach ($headers as $key => $value)
7685 $headers2[] = "$key: $value";
7687 if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
7689 curl_setopt($fp, CURLOPT_ENCODING, '');
7691 curl_setopt($fp, CURLOPT_URL, $url);
7692 curl_setopt($fp, CURLOPT_HEADER, 1);
7693 curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
7694 curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
7695 curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
7696 curl_setopt($fp, CURLOPT_REFERER, $url);
7697 curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
7698 curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
7699 if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
7701 curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
7702 curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
7705 $this->headers = curl_exec($fp);
7706 if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
7708 curl_setopt($fp, CURLOPT_ENCODING, 'none');
7709 $this->headers = curl_exec($fp);
7711 if (curl_errno($fp))
7713 $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
7714 $this->success = false;
7716 else
7718 $info = curl_getinfo($fp);
7719 curl_close($fp);
7720 $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
7721 $this->headers = array_pop($this->headers);
7722 $parser = new SimplePie_HTTP_Parser($this->headers);
7723 if ($parser->parse())
7725 $this->headers = $parser->headers;
7726 $this->body = $parser->body;
7727 $this->status_code = $parser->status_code;
7728 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)
7730 $this->redirects++;
7731 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
7732 return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
7737 else
7739 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
7740 $url_parts = parse_url($url);
7741 $socket_host = $url_parts['host'];
7742 if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
7744 $socket_host = "ssl://$url_parts[host]";
7745 $url_parts['port'] = 443;
7747 if (!isset($url_parts['port']))
7749 $url_parts['port'] = 80;
7751 $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
7752 if (!$fp)
7754 $this->error = 'fsockopen error: ' . $errstr;
7755 $this->success = false;
7757 else
7759 stream_set_timeout($fp, $timeout);
7760 if (isset($url_parts['path']))
7762 if (isset($url_parts['query']))
7764 $get = "$url_parts[path]?$url_parts[query]";
7766 else
7768 $get = $url_parts['path'];
7771 else
7773 $get = '/';
7775 $out = "GET $get HTTP/1.0\r\n";
7776 $out .= "Host: $url_parts[host]\r\n";
7777 $out .= "User-Agent: $useragent\r\n";
7778 if (extension_loaded('zlib'))
7780 $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
7783 if (isset($url_parts['user']) && isset($url_parts['pass']))
7785 $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
7787 foreach ($headers as $key => $value)
7789 $out .= "$key: $value\r\n";
7791 $out .= "Connection: Close\r\n\r\n";
7792 fwrite($fp, $out);
7794 $info = stream_get_meta_data($fp);
7796 $this->headers = '';
7797 while (!$info['eof'] && !$info['timed_out'])
7799 $this->headers .= fread($fp, 1160);
7800 $info = stream_get_meta_data($fp);
7802 if (!$info['timed_out'])
7804 $parser = new SimplePie_HTTP_Parser($this->headers);
7805 if ($parser->parse())
7807 $this->headers = $parser->headers;
7808 $this->body = $parser->body;
7809 $this->status_code = $parser->status_code;
7810 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)
7812 $this->redirects++;
7813 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
7814 return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
7816 if (isset($this->headers['content-encoding']))
7818 // Hey, we act dumb elsewhere, so let's do that here too
7819 switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
7821 case 'gzip':
7822 case 'x-gzip':
7823 $decoder = new SimplePie_gzdecode($this->body);
7824 if (!$decoder->parse())
7826 $this->error = 'Unable to decode HTTP "gzip" stream';
7827 $this->success = false;
7829 else
7831 $this->body = $decoder->data;
7833 break;
7835 case 'deflate':
7836 if (($body = gzuncompress($this->body)) === false)
7838 if (($body = gzinflate($this->body)) === false)
7840 $this->error = 'Unable to decode HTTP "deflate" stream';
7841 $this->success = false;
7844 $this->body = $body;
7845 break;
7847 default:
7848 $this->error = 'Unknown content coding';
7849 $this->success = false;
7854 else
7856 $this->error = 'fsocket timed out';
7857 $this->success = false;
7859 fclose($fp);
7863 else
7865 $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
7866 if (!$this->body = file_get_contents($url))
7868 $this->error = 'file_get_contents could not read the file';
7869 $this->success = false;
7876 * HTTP Response Parser
7878 * @package SimplePie
7880 class SimplePie_HTTP_Parser
7883 * HTTP Version
7885 * @access public
7886 * @var float
7888 var $http_version = 0.0;
7891 * Status code
7893 * @access public
7894 * @var int
7896 var $status_code = 0;
7899 * Reason phrase
7901 * @access public
7902 * @var string
7904 var $reason = '';
7907 * Key/value pairs of the headers
7909 * @access public
7910 * @var array
7912 var $headers = array();
7915 * Body of the response
7917 * @access public
7918 * @var string
7920 var $body = '';
7923 * Current state of the state machine
7925 * @access private
7926 * @var string
7928 var $state = 'http_version';
7931 * Input data
7933 * @access private
7934 * @var string
7936 var $data = '';
7939 * Input data length (to avoid calling strlen() everytime this is needed)
7941 * @access private
7942 * @var int
7944 var $data_length = 0;
7947 * Current position of the pointer
7949 * @var int
7950 * @access private
7952 var $position = 0;
7955 * Name of the hedaer currently being parsed
7957 * @access private
7958 * @var string
7960 var $name = '';
7963 * Value of the hedaer currently being parsed
7965 * @access private
7966 * @var string
7968 var $value = '';
7971 * Create an instance of the class with the input data
7973 * @access public
7974 * @param string $data Input data
7976 function SimplePie_HTTP_Parser($data)
7978 $this->data = $data;
7979 $this->data_length = strlen($this->data);
7983 * Parse the input data
7985 * @access public
7986 * @return bool true on success, false on failure
7988 function parse()
7990 while ($this->state && $this->state !== 'emit' && $this->has_data())
7992 $state = $this->state;
7993 $this->$state();
7995 $this->data = '';
7996 if ($this->state === 'emit' || $this->state === 'body')
7998 return true;
8000 else
8002 $this->http_version = '';
8003 $this->status_code = '';
8004 $this->reason = '';
8005 $this->headers = array();
8006 $this->body = '';
8007 return false;
8012 * Check whether there is data beyond the pointer
8014 * @access private
8015 * @return bool true if there is further data, false if not
8017 function has_data()
8019 return (bool) ($this->position < $this->data_length);
8023 * See if the next character is LWS
8025 * @access private
8026 * @return bool true if the next character is LWS, false if not
8028 function is_linear_whitespace()
8030 return (bool) ($this->data[$this->position] === "\x09"
8031 || $this->data[$this->position] === "\x20"
8032 || ($this->data[$this->position] === "\x0A"
8033 && isset($this->data[$this->position + 1])
8034 && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
8038 * Parse the HTTP version
8040 * @access private
8042 function http_version()
8044 if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
8046 $len = strspn($this->data, '0123456789.', 5);
8047 $this->http_version = substr($this->data, 5, $len);
8048 $this->position += 5 + $len;
8049 if (substr_count($this->http_version, '.') <= 1)
8051 $this->http_version = (float) $this->http_version;
8052 $this->position += strspn($this->data, "\x09\x20", $this->position);
8053 $this->state = 'status';
8055 else
8057 $this->state = false;
8060 else
8062 $this->state = false;
8067 * Parse the status code
8069 * @access private
8071 function status()
8073 if ($len = strspn($this->data, '0123456789', $this->position))
8075 $this->status_code = (int) substr($this->data, $this->position, $len);
8076 $this->position += $len;
8077 $this->state = 'reason';
8079 else
8081 $this->state = false;
8086 * Parse the reason phrase
8088 * @access private
8090 function reason()
8092 $len = strcspn($this->data, "\x0A", $this->position);
8093 $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
8094 $this->position += $len + 1;
8095 $this->state = 'new_line';
8099 * Deal with a new line, shifting data around as needed
8101 * @access private
8103 function new_line()
8105 $this->value = trim($this->value, "\x0D\x20");
8106 if ($this->name !== '' && $this->value !== '')
8108 $this->name = strtolower($this->name);
8109 if (isset($this->headers[$this->name]))
8111 $this->headers[$this->name] .= ', ' . $this->value;
8113 else
8115 $this->headers[$this->name] = $this->value;
8118 $this->name = '';
8119 $this->value = '';
8120 if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
8122 $this->position += 2;
8123 $this->state = 'body';
8125 elseif ($this->data[$this->position] === "\x0A")
8127 $this->position++;
8128 $this->state = 'body';
8130 else
8132 $this->state = 'name';
8137 * Parse a header name
8139 * @access private
8141 function name()
8143 $len = strcspn($this->data, "\x0A:", $this->position);
8144 if (isset($this->data[$this->position + $len]))
8146 if ($this->data[$this->position + $len] === "\x0A")
8148 $this->position += $len;
8149 $this->state = 'new_line';
8151 else
8153 $this->name = substr($this->data, $this->position, $len);
8154 $this->position += $len + 1;
8155 $this->state = 'value';
8158 else
8160 $this->state = false;
8165 * Parse LWS, replacing consecutive LWS characters with a single space
8167 * @access private
8169 function linear_whitespace()
8173 if (substr($this->data, $this->position, 2) === "\x0D\x0A")
8175 $this->position += 2;
8177 elseif ($this->data[$this->position] === "\x0A")
8179 $this->position++;
8181 $this->position += strspn($this->data, "\x09\x20", $this->position);
8182 } while ($this->has_data() && $this->is_linear_whitespace());
8183 $this->value .= "\x20";
8187 * See what state to move to while within non-quoted header values
8189 * @access private
8191 function value()
8193 if ($this->is_linear_whitespace())
8195 $this->linear_whitespace();
8197 else
8199 switch ($this->data[$this->position])
8201 case '"':
8202 $this->position++;
8203 $this->state = 'quote';
8204 break;
8206 case "\x0A":
8207 $this->position++;
8208 $this->state = 'new_line';
8209 break;
8211 default:
8212 $this->state = 'value_char';
8213 break;
8219 * Parse a header value while outside quotes
8221 * @access private
8223 function value_char()
8225 $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
8226 $this->value .= substr($this->data, $this->position, $len);
8227 $this->position += $len;
8228 $this->state = 'value';
8232 * See what state to move to while within quoted header values
8234 * @access private
8236 function quote()
8238 if ($this->is_linear_whitespace())
8240 $this->linear_whitespace();
8242 else
8244 switch ($this->data[$this->position])
8246 case '"':
8247 $this->position++;
8248 $this->state = 'value';
8249 break;
8251 case "\x0A":
8252 $this->position++;
8253 $this->state = 'new_line';
8254 break;
8256 case '\\':
8257 $this->position++;
8258 $this->state = 'quote_escaped';
8259 break;
8261 default:
8262 $this->state = 'quote_char';
8263 break;
8269 * Parse a header value while within quotes
8271 * @access private
8273 function quote_char()
8275 $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
8276 $this->value .= substr($this->data, $this->position, $len);
8277 $this->position += $len;
8278 $this->state = 'value';
8282 * Parse an escaped character within quotes
8284 * @access private
8286 function quote_escaped()
8288 $this->value .= $this->data[$this->position];
8289 $this->position++;
8290 $this->state = 'quote';
8294 * Parse the body
8296 * @access private
8298 function body()
8300 $this->body = substr($this->data, $this->position);
8301 $this->state = 'emit';
8306 * gzdecode
8308 * @package SimplePie
8310 class SimplePie_gzdecode
8313 * Compressed data
8315 * @access private
8316 * @see gzdecode::$data
8318 var $compressed_data;
8321 * Size of compressed data
8323 * @access private
8325 var $compressed_size;
8328 * Minimum size of a valid gzip string
8330 * @access private
8332 var $min_compressed_size = 18;
8335 * Current position of pointer
8337 * @access private
8339 var $position = 0;
8342 * Flags (FLG)
8344 * @access private
8346 var $flags;
8349 * Uncompressed data
8351 * @access public
8352 * @see gzdecode::$compressed_data
8354 var $data;
8357 * Modified time
8359 * @access public
8361 var $MTIME;
8364 * Extra Flags
8366 * @access public
8368 var $XFL;
8371 * Operating System
8373 * @access public
8375 var $OS;
8378 * Subfield ID 1
8380 * @access public
8381 * @see gzdecode::$extra_field
8382 * @see gzdecode::$SI2
8384 var $SI1;
8387 * Subfield ID 2
8389 * @access public
8390 * @see gzdecode::$extra_field
8391 * @see gzdecode::$SI1
8393 var $SI2;
8396 * Extra field content
8398 * @access public
8399 * @see gzdecode::$SI1
8400 * @see gzdecode::$SI2
8402 var $extra_field;
8405 * Original filename
8407 * @access public
8409 var $filename;
8412 * Human readable comment
8414 * @access public
8416 var $comment;
8419 * Don't allow anything to be set
8421 * @access public
8423 function __set($name, $value)
8425 trigger_error("Cannot write property $name", E_USER_ERROR);
8429 * Set the compressed string and related properties
8431 * @access public
8433 function SimplePie_gzdecode($data)
8435 $this->compressed_data = $data;
8436 $this->compressed_size = strlen($data);
8440 * Decode the GZIP stream
8442 * @access public
8444 function parse()
8446 if ($this->compressed_size >= $this->min_compressed_size)
8448 // Check ID1, ID2, and CM
8449 if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
8451 return false;
8454 // Get the FLG (FLaGs)
8455 $this->flags = ord($this->compressed_data[3]);
8457 // FLG bits above (1 << 4) are reserved
8458 if ($this->flags > 0x1F)
8460 return false;
8463 // Advance the pointer after the above
8464 $this->position += 4;
8466 // MTIME
8467 $mtime = substr($this->compressed_data, $this->position, 4);
8468 // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
8469 if (current(unpack('S', "\x00\x01")) === 1)
8471 $mtime = strrev($mtime);
8473 $this->MTIME = current(unpack('l', $mtime));
8474 $this->position += 4;
8476 // Get the XFL (eXtra FLags)
8477 $this->XFL = ord($this->compressed_data[$this->position++]);
8479 // Get the OS (Operating System)
8480 $this->OS = ord($this->compressed_data[$this->position++]);
8482 // Parse the FEXTRA
8483 if ($this->flags & 4)
8485 // Read subfield IDs
8486 $this->SI1 = $this->compressed_data[$this->position++];
8487 $this->SI2 = $this->compressed_data[$this->position++];
8489 // SI2 set to zero is reserved for future use
8490 if ($this->SI2 === "\x00")
8492 return false;
8495 // Get the length of the extra field
8496 $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
8497 $this->position += 2;
8499 // Check the length of the string is still valid
8500 $this->min_compressed_size += $len + 4;
8501 if ($this->compressed_size >= $this->min_compressed_size)
8503 // Set the extra field to the given data
8504 $this->extra_field = substr($this->compressed_data, $this->position, $len);
8505 $this->position += $len;
8507 else
8509 return false;
8513 // Parse the FNAME
8514 if ($this->flags & 8)
8516 // Get the length of the filename
8517 $len = strcspn($this->compressed_data, "\x00", $this->position);
8519 // Check the length of the string is still valid
8520 $this->min_compressed_size += $len + 1;
8521 if ($this->compressed_size >= $this->min_compressed_size)
8523 // Set the original filename to the given string
8524 $this->filename = substr($this->compressed_data, $this->position, $len);
8525 $this->position += $len + 1;
8527 else
8529 return false;
8533 // Parse the FCOMMENT
8534 if ($this->flags & 16)
8536 // Get the length of the comment
8537 $len = strcspn($this->compressed_data, "\x00", $this->position);
8539 // Check the length of the string is still valid
8540 $this->min_compressed_size += $len + 1;
8541 if ($this->compressed_size >= $this->min_compressed_size)
8543 // Set the original comment to the given string
8544 $this->comment = substr($this->compressed_data, $this->position, $len);
8545 $this->position += $len + 1;
8547 else
8549 return false;
8553 // Parse the FHCRC
8554 if ($this->flags & 2)
8556 // Check the length of the string is still valid
8557 $this->min_compressed_size += $len + 2;
8558 if ($this->compressed_size >= $this->min_compressed_size)
8560 // Read the CRC
8561 $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
8563 // Check the CRC matches
8564 if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
8566 $this->position += 2;
8568 else
8570 return false;
8573 else
8575 return false;
8579 // Decompress the actual data
8580 if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
8582 return false;
8584 else
8586 $this->position = $this->compressed_size - 8;
8589 // Check CRC of data
8590 $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
8591 $this->position += 4;
8592 /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
8594 return false;
8597 // Check ISIZE of data
8598 $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
8599 $this->position += 4;
8600 if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
8602 return false;
8605 // Wow, against all odds, we've actually got a valid gzip string
8606 return true;
8608 else
8610 return false;
8615 class SimplePie_Cache
8618 * Don't call the constructor. Please.
8620 * @access private
8622 function SimplePie_Cache()
8624 trigger_error('Please call SimplePie_Cache::create() instead of the constructor', E_USER_ERROR);
8628 * Create a new SimplePie_Cache object
8630 * @static
8631 * @access public
8633 function create($location, $filename, $extension)
8635 $location_iri = new SimplePie_IRI($location);
8636 switch ($location_iri->get_scheme())
8638 case 'mysql':
8639 if (extension_loaded('mysql'))
8641 return new SimplePie_Cache_MySQL($location_iri, $filename, $extension);
8643 break;
8645 default:
8646 return new SimplePie_Cache_File($location, $filename, $extension);
8651 class SimplePie_Cache_File
8653 var $location;
8654 var $filename;
8655 var $extension;
8656 var $name;
8658 function SimplePie_Cache_File($location, $filename, $extension)
8660 $this->location = $location;
8661 $this->filename = $filename;
8662 $this->extension = $extension;
8663 $this->name = "$this->location/$this->filename.$this->extension";
8666 function save($data)
8668 if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
8670 if (is_a($data, 'SimplePie'))
8672 $data = $data->data;
8675 $data = serialize($data);
8677 if (function_exists('file_put_contents'))
8679 return (bool) file_put_contents($this->name, $data);
8681 else
8683 $fp = fopen($this->name, 'wb');
8684 if ($fp)
8686 fwrite($fp, $data);
8687 fclose($fp);
8688 return true;
8692 return false;
8695 function load()
8697 if (file_exists($this->name) && is_readable($this->name))
8699 return unserialize(file_get_contents($this->name));
8701 return false;
8704 function mtime()
8706 if (file_exists($this->name))
8708 return filemtime($this->name);
8710 return false;
8713 function touch()
8715 if (file_exists($this->name))
8717 return touch($this->name);
8719 return false;
8722 function unlink()
8724 if (file_exists($this->name))
8726 return unlink($this->name);
8728 return false;
8732 class SimplePie_Cache_DB
8734 function prepare_simplepie_object_for_cache($data)
8736 $items = $data->get_items();
8737 $items_by_id = array();
8739 if (!empty($items))
8741 foreach ($items as $item)
8743 $items_by_id[$item->get_id()] = $item;
8746 if (count($items_by_id) !== count($items))
8748 $items_by_id = array();
8749 foreach ($items as $item)
8751 $items_by_id[$item->get_id(true)] = $item;
8755 if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
8757 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
8759 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
8761 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
8763 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
8765 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
8767 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
8769 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
8771 else
8773 $channel = null;
8776 if ($channel !== null)
8778 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
8780 unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
8782 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
8784 unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
8786 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
8788 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
8790 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
8792 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
8794 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
8796 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
8799 if (isset($data->data['items']))
8801 unset($data->data['items']);
8803 if (isset($data->data['ordered_items']))
8805 unset($data->data['ordered_items']);
8808 return array(serialize($data->data), $items_by_id);
8812 class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
8814 var $mysql;
8815 var $options;
8816 var $id;
8818 function SimplePie_Cache_MySQL($mysql_location, $name, $extension)
8820 $host = $mysql_location->get_host();
8821 if (SimplePie_Misc::stripos($host, 'unix(') === 0 && substr($host, -1) === ')')
8823 $server = ':' . substr($host, 5, -1);
8825 else
8827 $server = $host;
8828 if ($mysql_location->get_port() !== null)
8830 $server .= ':' . $mysql_location->get_port();
8834 if (strpos($mysql_location->get_userinfo(), ':') !== false)
8836 list($username, $password) = explode(':', $mysql_location->get_userinfo(), 2);
8838 else
8840 $username = $mysql_location->get_userinfo();
8841 $password = null;
8844 if ($this->mysql = mysql_connect($server, $username, $password))
8846 $this->id = $name . $extension;
8847 $this->options = SimplePie_Misc::parse_str($mysql_location->get_query());
8848 if (!isset($this->options['prefix'][0]))
8850 $this->options['prefix'][0] = '';
8853 if (mysql_select_db(ltrim($mysql_location->get_path(), '/'))
8854 && mysql_query('SET NAMES utf8')
8855 && ($query = mysql_unbuffered_query('SHOW TABLES')))
8857 $db = array();
8858 while ($row = mysql_fetch_row($query))
8860 $db[] = $row[0];
8863 if (!in_array($this->options['prefix'][0] . 'cache_data', $db))
8865 if (!mysql_query('CREATE TABLE `' . $this->options['prefix'][0] . '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)))'))
8867 $this->mysql = null;
8871 if (!in_array($this->options['prefix'][0] . 'items', $db))
8873 if (!mysql_query('CREATE TABLE `' . $this->options['prefix'][0] . '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)))'))
8875 $this->mysql = null;
8879 else
8881 $this->mysql = null;
8886 function save($data)
8888 if ($this->mysql)
8890 $feed_id = "'" . mysql_real_escape_string($this->id) . "'";
8892 if (is_a($data, 'SimplePie'))
8894 if (SIMPLEPIE_PHP5)
8896 // This keyword needs to defy coding standards for PHP4 compatibility
8897 $data = clone($data);
8900 $prepared = $this->prepare_simplepie_object_for_cache($data);
8902 if ($query = mysql_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = ' . $feed_id, $this->mysql))
8904 if (mysql_num_rows($query))
8906 $items = count($prepared[1]);
8907 if ($items)
8909 $sql = 'UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `items` = ' . $items . ', `data` = \'' . mysql_real_escape_string($prepared[0]) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id;
8911 else
8913 $sql = 'UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `data` = \'' . mysql_real_escape_string($prepared[0]) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id;
8916 if (!mysql_query($sql, $this->mysql))
8918 return false;
8921 elseif (!mysql_query('INSERT INTO `' . $this->options['prefix'][0] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(' . $feed_id . ', ' . count($prepared[1]) . ', \'' . mysql_real_escape_string($prepared[0]) . '\', ' . time() . ')', $this->mysql))
8923 return false;
8926 $ids = array_keys($prepared[1]);
8927 if (!empty($ids))
8929 foreach ($ids as $id)
8931 $database_ids[] = mysql_real_escape_string($id);
8934 if ($query = mysql_unbuffered_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'items` WHERE `id` = \'' . implode('\' OR `id` = \'', $database_ids) . '\' AND `feed_id` = ' . $feed_id, $this->mysql))
8936 $existing_ids = array();
8937 while ($row = mysql_fetch_row($query))
8939 $existing_ids[] = $row[0];
8942 $new_ids = array_diff($ids, $existing_ids);
8944 foreach ($new_ids as $new_id)
8946 if (!($date = $prepared[1][$new_id]->get_date('U')))
8948 $date = time();
8951 if (!mysql_query('INSERT INTO `' . $this->options['prefix'][0] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(' . $feed_id . ', \'' . mysql_real_escape_string($new_id) . '\', \'' . mysql_real_escape_string(serialize($prepared[1][$new_id]->data)) . '\', ' . $date . ')', $this->mysql))
8953 return false;
8956 return true;
8959 else
8961 return true;
8965 elseif ($query = mysql_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = ' . $feed_id, $this->mysql))
8967 if (mysql_num_rows($query))
8969 if (mysql_query('UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `items` = 0, `data` = \'' . mysql_real_escape_string(serialize($data)) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id, $this->mysql))
8971 return true;
8974 elseif (mysql_query('INSERT INTO `' . $this->options['prefix'][0] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(\'' . mysql_real_escape_string($this->id) . '\', 0, \'' . mysql_real_escape_string(serialize($data)) . '\', ' . time() . ')', $this->mysql))
8976 return true;
8980 return false;
8983 function load()
8985 if ($this->mysql && ($query = mysql_query('SELECT `items`, `data` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && ($row = mysql_fetch_row($query)))
8987 $data = unserialize($row[1]);
8989 if (isset($this->options['items'][0]))
8991 $items = (int) $this->options['items'][0];
8993 else
8995 $items = (int) $row[0];
8998 if ($items !== 0)
9000 if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
9002 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
9004 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
9006 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
9008 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
9010 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
9012 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
9014 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
9016 else
9018 $feed = null;
9021 if ($feed !== null)
9023 $sql = 'SELECT `data` FROM `' . $this->options['prefix'][0] . 'items` WHERE `feed_id` = \'' . mysql_real_escape_string($this->id) . '\' ORDER BY `posted` DESC';
9024 if ($items > 0)
9026 $sql .= ' LIMIT ' . $items;
9029 if ($query = mysql_unbuffered_query($sql, $this->mysql))
9031 while ($row = mysql_fetch_row($query))
9033 $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row[0]);
9036 else
9038 return false;
9042 return $data;
9044 return false;
9047 function mtime()
9049 if ($this->mysql && ($query = mysql_query('SELECT `mtime` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && ($row = mysql_fetch_row($query)))
9051 return $row[0];
9053 else
9055 return false;
9059 function touch()
9061 if ($this->mysql && ($query = mysql_query('UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `mtime` = ' . time() . ' WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && mysql_affected_rows($this->mysql))
9063 return true;
9065 else
9067 return false;
9071 function unlink()
9073 if ($this->mysql && ($query = mysql_query('DELETE FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && ($query2 = mysql_query('DELETE FROM `' . $this->options['prefix'][0] . 'items` WHERE `feed_id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)))
9075 return true;
9077 else
9079 return false;
9084 class SimplePie_Misc
9086 function time_hms($seconds)
9088 $time = '';
9090 $hours = floor($seconds / 3600);
9091 $remainder = $seconds % 3600;
9092 if ($hours > 0)
9094 $time .= $hours.':';
9097 $minutes = floor($remainder / 60);
9098 $seconds = $remainder % 60;
9099 if ($minutes < 10 && $hours > 0)
9101 $minutes = '0' . $minutes;
9103 if ($seconds < 10)
9105 $seconds = '0' . $seconds;
9108 $time .= $minutes.':';
9109 $time .= $seconds;
9111 return $time;
9114 function absolutize_url($relative, $base)
9116 $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
9117 return $iri->get_iri();
9120 function remove_dot_segments($input)
9122 $output = '';
9123 while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
9125 // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
9126 if (strpos($input, '../') === 0)
9128 $input = substr($input, 3);
9130 elseif (strpos($input, './') === 0)
9132 $input = substr($input, 2);
9134 // 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,
9135 elseif (strpos($input, '/./') === 0)
9137 $input = substr_replace($input, '/', 0, 3);
9139 elseif ($input === '/.')
9141 $input = '/';
9143 // 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,
9144 elseif (strpos($input, '/../') === 0)
9146 $input = substr_replace($input, '/', 0, 4);
9147 $output = substr_replace($output, '', strrpos($output, '/'));
9149 elseif ($input === '/..')
9151 $input = '/';
9152 $output = substr_replace($output, '', strrpos($output, '/'));
9154 // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
9155 elseif ($input === '.' || $input === '..')
9157 $input = '';
9159 // 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
9160 elseif (($pos = strpos($input, '/', 1)) !== false)
9162 $output .= substr($input, 0, $pos);
9163 $input = substr_replace($input, '', 0, $pos);
9165 else
9167 $output .= $input;
9168 $input = '';
9171 return $output . $input;
9174 function get_element($realname, $string)
9176 $return = array();
9177 $name = preg_quote($realname, '/');
9178 if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
9180 for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
9182 $return[$i]['tag'] = $realname;
9183 $return[$i]['full'] = $matches[$i][0][0];
9184 $return[$i]['offset'] = $matches[$i][0][1];
9185 if (strlen($matches[$i][3][0]) <= 2)
9187 $return[$i]['self_closing'] = true;
9189 else
9191 $return[$i]['self_closing'] = false;
9192 $return[$i]['content'] = $matches[$i][4][0];
9194 $return[$i]['attribs'] = array();
9195 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))
9197 for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
9199 if (count($attribs[$j]) === 2)
9201 $attribs[$j][2] = $attribs[$j][1];
9203 $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
9208 return $return;
9211 function element_implode($element)
9213 $full = "<$element[tag]";
9214 foreach ($element['attribs'] as $key => $value)
9216 $key = strtolower($key);
9217 $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
9219 if ($element['self_closing'])
9221 $full .= ' />';
9223 else
9225 $full .= ">$element[content]</$element[tag]>";
9227 return $full;
9230 function error($message, $level, $file, $line)
9232 if ((ini_get('error_reporting') & $level) > 0)
9234 switch ($level)
9236 case E_USER_ERROR:
9237 $note = 'PHP Error';
9238 break;
9239 case E_USER_WARNING:
9240 $note = 'PHP Warning';
9241 break;
9242 case E_USER_NOTICE:
9243 $note = 'PHP Notice';
9244 break;
9245 default:
9246 $note = 'Unknown Error';
9247 break;
9250 $log_error = true;
9251 if (!function_exists('error_log'))
9253 $log_error = false;
9256 $log_file = @ini_get('error_log');
9257 if (!empty($log_file) && ('syslog' != $log_file) && !@is_writable($log_file))
9259 $log_error = false;
9262 if ($log_error)
9264 @error_log("$note: $message in $file on line $line", 0);
9268 return $message;
9272 * If a file has been cached, retrieve and display it.
9274 * This is most useful for caching images (get_favicon(), etc.),
9275 * however it works for all cached files. This WILL NOT display ANY
9276 * file/image/page/whatever, but rather only display what has already
9277 * been cached by SimplePie.
9279 * @access public
9280 * @see SimplePie::get_favicon()
9281 * @param str $identifier_url URL that is used to identify the content.
9282 * This may or may not be the actual URL of the live content.
9283 * @param str $cache_location Location of SimplePie's cache. Defaults
9284 * to './cache'.
9285 * @param str $cache_extension The file extension that the file was
9286 * cached with. Defaults to 'spc'.
9287 * @param str $cache_class Name of the cache-handling class being used
9288 * in SimplePie. Defaults to 'SimplePie_Cache', and should be left
9289 * as-is unless you've overloaded the class.
9290 * @param str $cache_name_function Obsolete. Exists for backwards
9291 * compatibility reasons only.
9293 function display_cached_file($identifier_url, $cache_location = './cache', $cache_extension = 'spc', $cache_class = 'SimplePie_Cache', $cache_name_function = 'md5')
9295 $cache = call_user_func(array($cache_class, 'create'), $cache_location, $identifier_url, $cache_extension);
9297 if ($file = $cache->load())
9299 if (isset($file['headers']['content-type']))
9301 header('Content-type:' . $file['headers']['content-type']);
9303 else
9305 header('Content-type: application/octet-stream');
9307 header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
9308 echo $file['body'];
9309 exit;
9312 die('Cached file for ' . $identifier_url . ' cannot be found.');
9315 function fix_protocol($url, $http = 1)
9317 $url = SimplePie_Misc::normalize_url($url);
9318 $parsed = SimplePie_Misc::parse_url($url);
9319 if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https')
9321 return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http);
9324 if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url))
9326 return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http);
9329 if ($http === 2 && $parsed['scheme'] !== '')
9331 return "feed:$url";
9333 elseif ($http === 3 && strtolower($parsed['scheme']) === 'http')
9335 return substr_replace($url, 'podcast', 0, 4);
9337 elseif ($http === 4 && strtolower($parsed['scheme']) === 'http')
9339 return substr_replace($url, 'itpc', 0, 4);
9341 else
9343 return $url;
9347 function parse_url($url)
9349 $iri = new SimplePie_IRI($url);
9350 return array(
9351 'scheme' => (string) $iri->get_scheme(),
9352 'authority' => (string) $iri->get_authority(),
9353 'path' => (string) $iri->get_path(),
9354 'query' => (string) $iri->get_query(),
9355 'fragment' => (string) $iri->get_fragment()
9359 function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
9361 $iri = new SimplePie_IRI('');
9362 $iri->set_scheme($scheme);
9363 $iri->set_authority($authority);
9364 $iri->set_path($path);
9365 $iri->set_query($query);
9366 $iri->set_fragment($fragment);
9367 return $iri->get_iri();
9370 function normalize_url($url)
9372 $iri = new SimplePie_IRI($url);
9373 return $iri->get_iri();
9376 function percent_encoding_normalization($match)
9378 $integer = hexdec($match[1]);
9379 if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E)
9381 return chr($integer);
9383 else
9385 return strtoupper($match[0]);
9390 * Remove bad UTF-8 bytes
9392 * PCRE Pattern to locate bad bytes in a UTF-8 string comes from W3C
9393 * FAQ: Multilingual Forms (modified to include full ASCII range)
9395 * @author Geoffrey Sneddon
9396 * @see http://www.w3.org/International/questions/qa-forms-utf-8
9397 * @param string $str String to remove bad UTF-8 bytes from
9398 * @return string UTF-8 string
9400 function utf8_bad_replace($str)
9402 if (function_exists('iconv') && ($return = @iconv('UTF-8', 'UTF-8//IGNORE', $str)))
9404 return $return;
9406 elseif (function_exists('mb_convert_encoding') && ($return = @mb_convert_encoding($str, 'UTF-8', 'UTF-8')))
9408 return $return;
9410 elseif (preg_match_all('/(?:[\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})+/', $str, $matches))
9412 return implode("\xEF\xBF\xBD", $matches[0]);
9414 elseif ($str !== '')
9416 return "\xEF\xBF\xBD";
9418 else
9420 return '';
9425 * Converts a Windows-1252 encoded string to a UTF-8 encoded string
9427 * @static
9428 * @access public
9429 * @param string $string Windows-1252 encoded string
9430 * @return string UTF-8 encoded string
9432 function windows_1252_to_utf8($string)
9434 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");
9436 return strtr($string, $convert_table);
9439 function change_encoding($data, $input, $output)
9441 $input = SimplePie_Misc::encoding($input);
9442 $output = SimplePie_Misc::encoding($output);
9444 // We fail to fail on non US-ASCII bytes
9445 if ($input === 'US-ASCII')
9447 static $non_ascii_octects = '';
9448 if (!$non_ascii_octects)
9450 for ($i = 0x80; $i <= 0xFF; $i++)
9452 $non_ascii_octects .= chr($i);
9455 $data = substr($data, 0, strcspn($data, $non_ascii_octects));
9458 // This is first, as behaviour of this is completely predictable
9459 if ($input === 'windows-1252' && $output === 'UTF-8')
9461 return SimplePie_Misc::windows_1252_to_utf8($data);
9463 // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported).
9464 elseif (function_exists('mb_convert_encoding') && @mb_convert_encoding("\x80", 'UTF-16BE', $input) !== "\x00\x80" && in_array($input, mb_list_encodings()) && ($return = @mb_convert_encoding($data, $output, $input)))
9466 return $return;
9468 // This is last, as behaviour of this varies with OS userland and PHP version
9469 elseif (function_exists('iconv') && ($return = @iconv($input, $output, $data)))
9471 return $return;
9473 // If we can't do anything, just fail
9474 else
9476 return false;
9481 * Normalize an encoding name
9483 * This is automatically generated by create.php
9485 * To generate it, run `php create.php` on the command line, and copy the
9486 * output to replace this function.
9488 * @param string $charset Character set to standardise
9489 * @return string Standardised name
9491 function encoding($charset)
9493 // Normalization from UTS #22
9494 switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset)))
9496 case 'adobestandardencoding':
9497 case 'csadobestandardencoding':
9498 return 'Adobe-Standard-Encoding';
9500 case 'adobesymbolencoding':
9501 case 'cshppsmath':
9502 return 'Adobe-Symbol-Encoding';
9504 case 'ami1251':
9505 case 'amiga1251':
9506 return 'Amiga-1251';
9508 case 'ansix31101983':
9509 case 'csat5001983':
9510 case 'csiso99naplps':
9511 case 'isoir99':
9512 case 'naplps':
9513 return 'ANSI_X3.110-1983';
9515 case 'arabic7':
9516 case 'asmo449':
9517 case 'csiso89asmo449':
9518 case 'iso9036':
9519 case 'isoir89':
9520 return 'ASMO_449';
9522 case 'big5':
9523 case 'csbig5':
9524 return 'Big5';
9526 case 'big5hkscs':
9527 return 'Big5-HKSCS';
9529 case 'bocu1':
9530 case 'csbocu1':
9531 return 'BOCU-1';
9533 case 'brf':
9534 case 'csbrf':
9535 return 'BRF';
9537 case 'bs4730':
9538 case 'csiso4unitedkingdom':
9539 case 'gb':
9540 case 'iso646gb':
9541 case 'isoir4':
9542 case 'uk':
9543 return 'BS_4730';
9545 case 'bsviewdata':
9546 case 'csiso47bsviewdata':
9547 case 'isoir47':
9548 return 'BS_viewdata';
9550 case 'cesu8':
9551 case 'cscesu8':
9552 return 'CESU-8';
9554 case 'ca':
9555 case 'csa71':
9556 case 'csaz243419851':
9557 case 'csiso121canadian1':
9558 case 'iso646ca':
9559 case 'isoir121':
9560 return 'CSA_Z243.4-1985-1';
9562 case 'csa72':
9563 case 'csaz243419852':
9564 case 'csiso122canadian2':
9565 case 'iso646ca2':
9566 case 'isoir122':
9567 return 'CSA_Z243.4-1985-2';
9569 case 'csaz24341985gr':
9570 case 'csiso123csaz24341985gr':
9571 case 'isoir123':
9572 return 'CSA_Z243.4-1985-gr';
9574 case 'csiso139csn369103':
9575 case 'csn369103':
9576 case 'isoir139':
9577 return 'CSN_369103';
9579 case 'csdecmcs':
9580 case 'dec':
9581 case 'decmcs':
9582 return 'DEC-MCS';
9584 case 'csiso21german':
9585 case 'de':
9586 case 'din66003':
9587 case 'iso646de':
9588 case 'isoir21':
9589 return 'DIN_66003';
9591 case 'csdkus':
9592 case 'dkus':
9593 return 'dk-us';
9595 case 'csiso646danish':
9596 case 'dk':
9597 case 'ds2089':
9598 case 'iso646dk':
9599 return 'DS_2089';
9601 case 'csibmebcdicatde':
9602 case 'ebcdicatde':
9603 return 'EBCDIC-AT-DE';
9605 case 'csebcdicatdea':
9606 case 'ebcdicatdea':
9607 return 'EBCDIC-AT-DE-A';
9609 case 'csebcdiccafr':
9610 case 'ebcdiccafr':
9611 return 'EBCDIC-CA-FR';
9613 case 'csebcdicdkno':
9614 case 'ebcdicdkno':
9615 return 'EBCDIC-DK-NO';
9617 case 'csebcdicdknoa':
9618 case 'ebcdicdknoa':
9619 return 'EBCDIC-DK-NO-A';
9621 case 'csebcdices':
9622 case 'ebcdices':
9623 return 'EBCDIC-ES';
9625 case 'csebcdicesa':
9626 case 'ebcdicesa':
9627 return 'EBCDIC-ES-A';
9629 case 'csebcdicess':
9630 case 'ebcdicess':
9631 return 'EBCDIC-ES-S';
9633 case 'csebcdicfise':
9634 case 'ebcdicfise':
9635 return 'EBCDIC-FI-SE';
9637 case 'csebcdicfisea':
9638 case 'ebcdicfisea':
9639 return 'EBCDIC-FI-SE-A';
9641 case 'csebcdicfr':
9642 case 'ebcdicfr':
9643 return 'EBCDIC-FR';
9645 case 'csebcdicit':
9646 case 'ebcdicit':
9647 return 'EBCDIC-IT';
9649 case 'csebcdicpt':
9650 case 'ebcdicpt':
9651 return 'EBCDIC-PT';
9653 case 'csebcdicuk':
9654 case 'ebcdicuk':
9655 return 'EBCDIC-UK';
9657 case 'csebcdicus':
9658 case 'ebcdicus':
9659 return 'EBCDIC-US';
9661 case 'csiso111ecmacyrillic':
9662 case 'ecmacyrillic':
9663 case 'isoir111':
9664 case 'koi8e':
9665 return 'ECMA-cyrillic';
9667 case 'csiso17spanish':
9668 case 'es':
9669 case 'iso646es':
9670 case 'isoir17':
9671 return 'ES';
9673 case 'csiso85spanish2':
9674 case 'es2':
9675 case 'iso646es2':
9676 case 'isoir85':
9677 return 'ES2';
9679 case 'cseucpkdfmtjapanese':
9680 case 'eucjp':
9681 case 'extendedunixcodepackedformatforjapanese':
9682 return 'EUC-JP';
9684 case 'cseucfixwidjapanese':
9685 case 'extendedunixcodefixedwidthforjapanese':
9686 return 'Extended_UNIX_Code_Fixed_Width_for_Japanese';
9688 case 'gb18030':
9689 return 'GB18030';
9691 case 'chinese':
9692 case 'cp936':
9693 case 'csgb2312':
9694 case 'csiso58gb231280':
9695 case 'gb2312':
9696 case 'gb231280':
9697 case 'gbk':
9698 case 'isoir58':
9699 case 'ms936':
9700 case 'windows936':
9701 return 'GBK';
9703 case 'cn':
9704 case 'csiso57gb1988':
9705 case 'gb198880':
9706 case 'iso646cn':
9707 case 'isoir57':
9708 return 'GB_1988-80';
9710 case 'csiso153gost1976874':
9711 case 'gost1976874':
9712 case 'isoir153':
9713 case 'stsev35888':
9714 return 'GOST_19768-74';
9716 case 'csiso150':
9717 case 'csiso150greekccitt':
9718 case 'greekccitt':
9719 case 'isoir150':
9720 return 'greek-ccitt';
9722 case 'csiso88greek7':
9723 case 'greek7':
9724 case 'isoir88':
9725 return 'greek7';
9727 case 'csiso18greek7old':
9728 case 'greek7old':
9729 case 'isoir18':
9730 return 'greek7-old';
9732 case 'cshpdesktop':
9733 case 'hpdesktop':
9734 return 'HP-DeskTop';
9736 case 'cshplegal':
9737 case 'hplegal':
9738 return 'HP-Legal';
9740 case 'cshpmath8':
9741 case 'hpmath8':
9742 return 'HP-Math8';
9744 case 'cshppifont':
9745 case 'hppifont':
9746 return 'HP-Pi-font';
9748 case 'cshproman8':
9749 case 'hproman8':
9750 case 'r8':
9751 case 'roman8':
9752 return 'hp-roman8';
9754 case 'hzgb2312':
9755 return 'HZ-GB-2312';
9757 case 'csibmsymbols':
9758 case 'ibmsymbols':
9759 return 'IBM-Symbols';
9761 case 'csibmthai':
9762 case 'ibmthai':
9763 return 'IBM-Thai';
9765 case 'cp37':
9766 case 'csibm37':
9767 case 'ebcdiccpca':
9768 case 'ebcdiccpnl':
9769 case 'ebcdiccpus':
9770 case 'ebcdiccpwt':
9771 case 'ibm37':
9772 return 'IBM037';
9774 case 'cp38':
9775 case 'csibm38':
9776 case 'ebcdicint':
9777 case 'ibm38':
9778 return 'IBM038';
9780 case 'cp273':
9781 case 'csibm273':
9782 case 'ibm273':
9783 return 'IBM273';
9785 case 'cp274':
9786 case 'csibm274':
9787 case 'ebcdicbe':
9788 case 'ibm274':
9789 return 'IBM274';
9791 case 'cp275':
9792 case 'csibm275':
9793 case 'ebcdicbr':
9794 case 'ibm275':
9795 return 'IBM275';
9797 case 'csibm277':
9798 case 'ebcdiccpdk':
9799 case 'ebcdiccpno':
9800 case 'ibm277':
9801 return 'IBM277';
9803 case 'cp278':
9804 case 'csibm278':
9805 case 'ebcdiccpfi':
9806 case 'ebcdiccpse':
9807 case 'ibm278':
9808 return 'IBM278';
9810 case 'cp280':
9811 case 'csibm280':
9812 case 'ebcdiccpit':
9813 case 'ibm280':
9814 return 'IBM280';
9816 case 'cp281':
9817 case 'csibm281':
9818 case 'ebcdicjpe':
9819 case 'ibm281':
9820 return 'IBM281';
9822 case 'cp284':
9823 case 'csibm284':
9824 case 'ebcdiccpes':
9825 case 'ibm284':
9826 return 'IBM284';
9828 case 'cp285':
9829 case 'csibm285':
9830 case 'ebcdiccpgb':
9831 case 'ibm285':
9832 return 'IBM285';
9834 case 'cp290':
9835 case 'csibm290':
9836 case 'ebcdicjpkana':
9837 case 'ibm290':
9838 return 'IBM290';
9840 case 'cp297':
9841 case 'csibm297':
9842 case 'ebcdiccpfr':
9843 case 'ibm297':
9844 return 'IBM297';
9846 case 'cp420':
9847 case 'csibm420':
9848 case 'ebcdiccpar1':
9849 case 'ibm420':
9850 return 'IBM420';
9852 case 'cp423':
9853 case 'csibm423':
9854 case 'ebcdiccpgr':
9855 case 'ibm423':
9856 return 'IBM423';
9858 case 'cp424':
9859 case 'csibm424':
9860 case 'ebcdiccphe':
9861 case 'ibm424':
9862 return 'IBM424';
9864 case '437':
9865 case 'cp437':
9866 case 'cspc8codepage437':
9867 case 'ibm437':
9868 return 'IBM437';
9870 case 'cp500':
9871 case 'csibm500':
9872 case 'ebcdiccpbe':
9873 case 'ebcdiccpch':
9874 case 'ibm500':
9875 return 'IBM500';
9877 case 'cp775':
9878 case 'cspc775baltic':
9879 case 'ibm775':
9880 return 'IBM775';
9882 case '850':
9883 case 'cp850':
9884 case 'cspc850multilingual':
9885 case 'ibm850':
9886 return 'IBM850';
9888 case '851':
9889 case 'cp851':
9890 case 'csibm851':
9891 case 'ibm851':
9892 return 'IBM851';
9894 case '852':
9895 case 'cp852':
9896 case 'cspcp852':
9897 case 'ibm852':
9898 return 'IBM852';
9900 case '855':
9901 case 'cp855':
9902 case 'csibm855':
9903 case 'ibm855':
9904 return 'IBM855';
9906 case '857':
9907 case 'cp857':
9908 case 'csibm857':
9909 case 'ibm857':
9910 return 'IBM857';
9912 case 'ccsid858':
9913 case 'cp858':
9914 case 'ibm858':
9915 case 'pcmultilingual850euro':
9916 return 'IBM00858';
9918 case '860':
9919 case 'cp860':
9920 case 'csibm860':
9921 case 'ibm860':
9922 return 'IBM860';
9924 case '861':
9925 case 'cp861':
9926 case 'cpis':
9927 case 'csibm861':
9928 case 'ibm861':
9929 return 'IBM861';
9931 case '862':
9932 case 'cp862':
9933 case 'cspc862latinhebrew':
9934 case 'ibm862':
9935 return 'IBM862';
9937 case '863':
9938 case 'cp863':
9939 case 'csibm863':
9940 case 'ibm863':
9941 return 'IBM863';
9943 case 'cp864':
9944 case 'csibm864':
9945 case 'ibm864':
9946 return 'IBM864';
9948 case '865':
9949 case 'cp865':
9950 case 'csibm865':
9951 case 'ibm865':
9952 return 'IBM865';
9954 case '866':
9955 case 'cp866':
9956 case 'csibm866':
9957 case 'ibm866':
9958 return 'IBM866';
9960 case 'cp868':
9961 case 'cpar':
9962 case 'csibm868':
9963 case 'ibm868':
9964 return 'IBM868';
9966 case '869':
9967 case 'cp869':
9968 case 'cpgr':
9969 case 'csibm869':
9970 case 'ibm869':
9971 return 'IBM869';
9973 case 'cp870':
9974 case 'csibm870':
9975 case 'ebcdiccproece':
9976 case 'ebcdiccpyu':
9977 case 'ibm870':
9978 return 'IBM870';
9980 case 'cp871':
9981 case 'csibm871':
9982 case 'ebcdiccpis':
9983 case 'ibm871':
9984 return 'IBM871';
9986 case 'cp880':
9987 case 'csibm880':
9988 case 'ebcdiccyrillic':
9989 case 'ibm880':
9990 return 'IBM880';
9992 case 'cp891':
9993 case 'csibm891':
9994 case 'ibm891':
9995 return 'IBM891';
9997 case 'cp903':
9998 case 'csibm903':
9999 case 'ibm903':
10000 return 'IBM903';
10002 case '904':
10003 case 'cp904':
10004 case 'csibbm904':
10005 case 'ibm904':
10006 return 'IBM904';
10008 case 'cp905':
10009 case 'csibm905':
10010 case 'ebcdiccptr':
10011 case 'ibm905':
10012 return 'IBM905';
10014 case 'cp918':
10015 case 'csibm918':
10016 case 'ebcdiccpar2':
10017 case 'ibm918':
10018 return 'IBM918';
10020 case 'ccsid924':
10021 case 'cp924':
10022 case 'ebcdiclatin9euro':
10023 case 'ibm924':
10024 return 'IBM00924';
10026 case 'cp1026':
10027 case 'csibm1026':
10028 case 'ibm1026':
10029 return 'IBM1026';
10031 case 'ibm1047':
10032 return 'IBM1047';
10034 case 'ccsid1140':
10035 case 'cp1140':
10036 case 'ebcdicus37euro':
10037 case 'ibm1140':
10038 return 'IBM01140';
10040 case 'ccsid1141':
10041 case 'cp1141':
10042 case 'ebcdicde273euro':
10043 case 'ibm1141':
10044 return 'IBM01141';
10046 case 'ccsid1142':
10047 case 'cp1142':
10048 case 'ebcdicdk277euro':
10049 case 'ebcdicno277euro':
10050 case 'ibm1142':
10051 return 'IBM01142';
10053 case 'ccsid1143':
10054 case 'cp1143':
10055 case 'ebcdicfi278euro':
10056 case 'ebcdicse278euro':
10057 case 'ibm1143':
10058 return 'IBM01143';
10060 case 'ccsid1144':
10061 case 'cp1144':
10062 case 'ebcdicit280euro':
10063 case 'ibm1144':
10064 return 'IBM01144';
10066 case 'ccsid1145':
10067 case 'cp1145':
10068 case 'ebcdices284euro':
10069 case 'ibm1145':
10070 return 'IBM01145';
10072 case 'ccsid1146':
10073 case 'cp1146':
10074 case 'ebcdicgb285euro':
10075 case 'ibm1146':
10076 return 'IBM01146';
10078 case 'ccsid1147':
10079 case 'cp1147':
10080 case 'ebcdicfr297euro':
10081 case 'ibm1147':
10082 return 'IBM01147';
10084 case 'ccsid1148':
10085 case 'cp1148':
10086 case 'ebcdicinternational500euro':
10087 case 'ibm1148':
10088 return 'IBM01148';
10090 case 'ccsid1149':
10091 case 'cp1149':
10092 case 'ebcdicis871euro':
10093 case 'ibm1149':
10094 return 'IBM01149';
10096 case 'csiso143iecp271':
10097 case 'iecp271':
10098 case 'isoir143':
10099 return 'IEC_P27-1';
10101 case 'csiso49inis':
10102 case 'inis':
10103 case 'isoir49':
10104 return 'INIS';
10106 case 'csiso50inis8':
10107 case 'inis8':
10108 case 'isoir50':
10109 return 'INIS-8';
10111 case 'csiso51iniscyrillic':
10112 case 'iniscyrillic':
10113 case 'isoir51':
10114 return 'INIS-cyrillic';
10116 case 'csinvariant':
10117 case 'invariant':
10118 return 'INVARIANT';
10120 case 'iso2022cn':
10121 return 'ISO-2022-CN';
10123 case 'iso2022cnext':
10124 return 'ISO-2022-CN-EXT';
10126 case 'csiso2022jp':
10127 case 'iso2022jp':
10128 return 'ISO-2022-JP';
10130 case 'csiso2022jp2':
10131 case 'iso2022jp2':
10132 return 'ISO-2022-JP-2';
10134 case 'csiso2022kr':
10135 case 'iso2022kr':
10136 return 'ISO-2022-KR';
10138 case 'cswindows30latin1':
10139 case 'iso88591windows30latin1':
10140 return 'ISO-8859-1-Windows-3.0-Latin-1';
10142 case 'cswindows31latin1':
10143 case 'iso88591windows31latin1':
10144 return 'ISO-8859-1-Windows-3.1-Latin-1';
10146 case 'csisolatin2':
10147 case 'iso88592':
10148 case 'iso885921987':
10149 case 'isoir101':
10150 case 'l2':
10151 case 'latin2':
10152 return 'ISO-8859-2';
10154 case 'cswindows31latin2':
10155 case 'iso88592windowslatin2':
10156 return 'ISO-8859-2-Windows-Latin-2';
10158 case 'csisolatin3':
10159 case 'iso88593':
10160 case 'iso885931988':
10161 case 'isoir109':
10162 case 'l3':
10163 case 'latin3':
10164 return 'ISO-8859-3';
10166 case 'csisolatin4':
10167 case 'iso88594':
10168 case 'iso885941988':
10169 case 'isoir110':
10170 case 'l4':
10171 case 'latin4':
10172 return 'ISO-8859-4';
10174 case 'csisolatincyrillic':
10175 case 'cyrillic':
10176 case 'iso88595':
10177 case 'iso885951988':
10178 case 'isoir144':
10179 return 'ISO-8859-5';
10181 case 'arabic':
10182 case 'asmo708':
10183 case 'csisolatinarabic':
10184 case 'ecma114':
10185 case 'iso88596':
10186 case 'iso885961987':
10187 case 'isoir127':
10188 return 'ISO-8859-6';
10190 case 'csiso88596e':
10191 case 'iso88596e':
10192 return 'ISO-8859-6-E';
10194 case 'csiso88596i':
10195 case 'iso88596i':
10196 return 'ISO-8859-6-I';
10198 case 'csisolatingreek':
10199 case 'ecma118':
10200 case 'elot928':
10201 case 'greek':
10202 case 'greek8':
10203 case 'iso88597':
10204 case 'iso885971987':
10205 case 'isoir126':
10206 return 'ISO-8859-7';
10208 case 'csisolatinhebrew':
10209 case 'hebrew':
10210 case 'iso88598':
10211 case 'iso885981988':
10212 case 'isoir138':
10213 return 'ISO-8859-8';
10215 case 'csiso88598e':
10216 case 'iso88598e':
10217 return 'ISO-8859-8-E';
10219 case 'csiso88598i':
10220 case 'iso88598i':
10221 return 'ISO-8859-8-I';
10223 case 'cswindows31latin5':
10224 case 'iso88599windowslatin5':
10225 return 'ISO-8859-9-Windows-Latin-5';
10227 case 'csisolatin6':
10228 case 'iso885910':
10229 case 'iso8859101992':
10230 case 'isoir157':
10231 case 'l6':
10232 case 'latin6':
10233 return 'ISO-8859-10';
10235 case 'iso885913':
10236 return 'ISO-8859-13';
10238 case 'iso885914':
10239 case 'iso8859141998':
10240 case 'isoceltic':
10241 case 'isoir199':
10242 case 'l8':
10243 case 'latin8':
10244 return 'ISO-8859-14';
10246 case 'iso885915':
10247 case 'latin9':
10248 return 'ISO-8859-15';
10250 case 'iso885916':
10251 case 'iso8859162001':
10252 case 'isoir226':
10253 case 'l10':
10254 case 'latin10':
10255 return 'ISO-8859-16';
10257 case 'iso10646j1':
10258 return 'ISO-10646-J-1';
10260 case 'csunicode':
10261 case 'iso10646ucs2':
10262 return 'ISO-10646-UCS-2';
10264 case 'csucs4':
10265 case 'iso10646ucs4':
10266 return 'ISO-10646-UCS-4';
10268 case 'csunicodeascii':
10269 case 'iso10646ucsbasic':
10270 return 'ISO-10646-UCS-Basic';
10272 case 'csunicodelatin1':
10273 case 'iso10646':
10274 case 'iso10646unicodelatin1':
10275 return 'ISO-10646-Unicode-Latin1';
10277 case 'csiso10646utf1':
10278 case 'iso10646utf1':
10279 return 'ISO-10646-UTF-1';
10281 case 'csiso115481':
10282 case 'iso115481':
10283 case 'isotr115481':
10284 return 'ISO-11548-1';
10286 case 'csiso90':
10287 case 'isoir90':
10288 return 'iso-ir-90';
10290 case 'csunicodeibm1261':
10291 case 'isounicodeibm1261':
10292 return 'ISO-Unicode-IBM-1261';
10294 case 'csunicodeibm1264':
10295 case 'isounicodeibm1264':
10296 return 'ISO-Unicode-IBM-1264';
10298 case 'csunicodeibm1265':
10299 case 'isounicodeibm1265':
10300 return 'ISO-Unicode-IBM-1265';
10302 case 'csunicodeibm1268':
10303 case 'isounicodeibm1268':
10304 return 'ISO-Unicode-IBM-1268';
10306 case 'csunicodeibm1276':
10307 case 'isounicodeibm1276':
10308 return 'ISO-Unicode-IBM-1276';
10310 case 'csiso646basic1983':
10311 case 'iso646basic1983':
10312 case 'ref':
10313 return 'ISO_646.basic:1983';
10315 case 'csiso2intlrefversion':
10316 case 'irv':
10317 case 'iso646irv1983':
10318 case 'isoir2':
10319 return 'ISO_646.irv:1983';
10321 case 'csiso2033':
10322 case 'e13b':
10323 case 'iso20331983':
10324 case 'isoir98':
10325 return 'ISO_2033-1983';
10327 case 'csiso5427cyrillic':
10328 case 'iso5427':
10329 case 'isoir37':
10330 return 'ISO_5427';
10332 case 'iso5427cyrillic1981':
10333 case 'iso54271981':
10334 case 'isoir54':
10335 return 'ISO_5427:1981';
10337 case 'csiso5428greek':
10338 case 'iso54281980':
10339 case 'isoir55':
10340 return 'ISO_5428:1980';
10342 case 'csiso6937add':
10343 case 'iso6937225':
10344 case 'isoir152':
10345 return 'ISO_6937-2-25';
10347 case 'csisotextcomm':
10348 case 'iso69372add':
10349 case 'isoir142':
10350 return 'ISO_6937-2-add';
10352 case 'csiso8859supp':
10353 case 'iso8859supp':
10354 case 'isoir154':
10355 case 'latin125':
10356 return 'ISO_8859-supp';
10358 case 'csiso10367box':
10359 case 'iso10367box':
10360 case 'isoir155':
10361 return 'ISO_10367-box';
10363 case 'csiso15italian':
10364 case 'iso646it':
10365 case 'isoir15':
10366 case 'it':
10367 return 'IT';
10369 case 'csiso13jisc6220jp':
10370 case 'isoir13':
10371 case 'jisc62201969':
10372 case 'jisc62201969jp':
10373 case 'katakana':
10374 case 'x2017':
10375 return 'JIS_C6220-1969-jp';
10377 case 'csiso14jisc6220ro':
10378 case 'iso646jp':
10379 case 'isoir14':
10380 case 'jisc62201969ro':
10381 case 'jp':
10382 return 'JIS_C6220-1969-ro';
10384 case 'csiso42jisc62261978':
10385 case 'isoir42':
10386 case 'jisc62261978':
10387 return 'JIS_C6226-1978';
10389 case 'csiso87jisx208':
10390 case 'isoir87':
10391 case 'jisc62261983':
10392 case 'jisx2081983':
10393 case 'x208':
10394 return 'JIS_C6226-1983';
10396 case 'csiso91jisc62291984a':
10397 case 'isoir91':
10398 case 'jisc62291984a':
10399 case 'jpocra':
10400 return 'JIS_C6229-1984-a';
10402 case 'csiso92jisc62991984b':
10403 case 'iso646jpocrb':
10404 case 'isoir92':
10405 case 'jisc62291984b':
10406 case 'jpocrb':
10407 return 'JIS_C6229-1984-b';
10409 case 'csiso93jis62291984badd':
10410 case 'isoir93':
10411 case 'jisc62291984badd':
10412 case 'jpocrbadd':
10413 return 'JIS_C6229-1984-b-add';
10415 case 'csiso94jis62291984hand':
10416 case 'isoir94':
10417 case 'jisc62291984hand':
10418 case 'jpocrhand':
10419 return 'JIS_C6229-1984-hand';
10421 case 'csiso95jis62291984handadd':
10422 case 'isoir95':
10423 case 'jisc62291984handadd':
10424 case 'jpocrhandadd':
10425 return 'JIS_C6229-1984-hand-add';
10427 case 'csiso96jisc62291984kana':
10428 case 'isoir96':
10429 case 'jisc62291984kana':
10430 return 'JIS_C6229-1984-kana';
10432 case 'csjisencoding':
10433 case 'jisencoding':
10434 return 'JIS_Encoding';
10436 case 'cshalfwidthkatakana':
10437 case 'jisx201':
10438 case 'x201':
10439 return 'JIS_X0201';
10441 case 'csiso159jisx2121990':
10442 case 'isoir159':
10443 case 'jisx2121990':
10444 case 'x212':
10445 return 'JIS_X0212-1990';
10447 case 'csiso141jusib1002':
10448 case 'iso646yu':
10449 case 'isoir141':
10450 case 'js':
10451 case 'jusib1002':
10452 case 'yu':
10453 return 'JUS_I.B1.002';
10455 case 'csiso147macedonian':
10456 case 'isoir147':
10457 case 'jusib1003mac':
10458 case 'macedonian':
10459 return 'JUS_I.B1.003-mac';
10461 case 'csiso146serbian':
10462 case 'isoir146':
10463 case 'jusib1003serb':
10464 case 'serbian':
10465 return 'JUS_I.B1.003-serb';
10467 case 'koi7switched':
10468 return 'KOI7-switched';
10470 case 'cskoi8r':
10471 case 'koi8r':
10472 return 'KOI8-R';
10474 case 'koi8u':
10475 return 'KOI8-U';
10477 case 'csksc5636':
10478 case 'iso646kr':
10479 case 'ksc5636':
10480 return 'KSC5636';
10482 case 'cskz1048':
10483 case 'kz1048':
10484 case 'rk1048':
10485 case 'strk10482002':
10486 return 'KZ-1048';
10488 case 'csiso19latingreek':
10489 case 'isoir19':
10490 case 'latingreek':
10491 return 'latin-greek';
10493 case 'csiso27latingreek1':
10494 case 'isoir27':
10495 case 'latingreek1':
10496 return 'Latin-greek-1';
10498 case 'csiso158lap':
10499 case 'isoir158':
10500 case 'lap':
10501 case 'latinlap':
10502 return 'latin-lap';
10504 case 'csmacintosh':
10505 case 'mac':
10506 case 'macintosh':
10507 return 'macintosh';
10509 case 'csmicrosoftpublishing':
10510 case 'microsoftpublishing':
10511 return 'Microsoft-Publishing';
10513 case 'csmnem':
10514 case 'mnem':
10515 return 'MNEM';
10517 case 'csmnemonic':
10518 case 'mnemonic':
10519 return 'MNEMONIC';
10521 case 'csiso86hungarian':
10522 case 'hu':
10523 case 'iso646hu':
10524 case 'isoir86':
10525 case 'msz77953':
10526 return 'MSZ_7795.3';
10528 case 'csnatsdano':
10529 case 'isoir91':
10530 case 'natsdano':
10531 return 'NATS-DANO';
10533 case 'csnatsdanoadd':
10534 case 'isoir92':
10535 case 'natsdanoadd':
10536 return 'NATS-DANO-ADD';
10538 case 'csnatssefi':
10539 case 'isoir81':
10540 case 'natssefi':
10541 return 'NATS-SEFI';
10543 case 'csnatssefiadd':
10544 case 'isoir82':
10545 case 'natssefiadd':
10546 return 'NATS-SEFI-ADD';
10548 case 'csiso151cuba':
10549 case 'cuba':
10550 case 'iso646cu':
10551 case 'isoir151':
10552 case 'ncnc1081':
10553 return 'NC_NC00-10:81';
10555 case 'csiso69french':
10556 case 'fr':
10557 case 'iso646fr':
10558 case 'isoir69':
10559 case 'nfz62010':
10560 return 'NF_Z_62-010';
10562 case 'csiso25french':
10563 case 'iso646fr1':
10564 case 'isoir25':
10565 case 'nfz620101973':
10566 return 'NF_Z_62-010_(1973)';
10568 case 'csiso60danishnorwegian':
10569 case 'csiso60norwegian1':
10570 case 'iso646no':
10571 case 'isoir60':
10572 case 'no':
10573 case 'ns45511':
10574 return 'NS_4551-1';
10576 case 'csiso61norwegian2':
10577 case 'iso646no2':
10578 case 'isoir61':
10579 case 'no2':
10580 case 'ns45512':
10581 return 'NS_4551-2';
10583 case 'osdebcdicdf3irv':
10584 return 'OSD_EBCDIC_DF03_IRV';
10586 case 'osdebcdicdf41':
10587 return 'OSD_EBCDIC_DF04_1';
10589 case 'osdebcdicdf415':
10590 return 'OSD_EBCDIC_DF04_15';
10592 case 'cspc8danishnorwegian':
10593 case 'pc8danishnorwegian':
10594 return 'PC8-Danish-Norwegian';
10596 case 'cspc8turkish':
10597 case 'pc8turkish':
10598 return 'PC8-Turkish';
10600 case 'csiso16portuguese':
10601 case 'iso646pt':
10602 case 'isoir16':
10603 case 'pt':
10604 return 'PT';
10606 case 'csiso84portuguese2':
10607 case 'iso646pt2':
10608 case 'isoir84':
10609 case 'pt2':
10610 return 'PT2';
10612 case 'cp154':
10613 case 'csptcp154':
10614 case 'cyrillicasian':
10615 case 'pt154':
10616 case 'ptcp154':
10617 return 'PTCP154';
10619 case 'scsu':
10620 return 'SCSU';
10622 case 'csiso10swedish':
10623 case 'fi':
10624 case 'iso646fi':
10625 case 'iso646se':
10626 case 'isoir10':
10627 case 'se':
10628 case 'sen850200b':
10629 return 'SEN_850200_B';
10631 case 'csiso11swedishfornames':
10632 case 'iso646se2':
10633 case 'isoir11':
10634 case 'se2':
10635 case 'sen850200c':
10636 return 'SEN_850200_C';
10638 case 'csiso102t617bit':
10639 case 'isoir102':
10640 case 't617bit':
10641 return 'T.61-7bit';
10643 case 'csiso103t618bit':
10644 case 'isoir103':
10645 case 't61':
10646 case 't618bit':
10647 return 'T.61-8bit';
10649 case 'csiso128t101g2':
10650 case 'isoir128':
10651 case 't101g2':
10652 return 'T.101-G2';
10654 case 'cstscii':
10655 case 'tscii':
10656 return 'TSCII';
10658 case 'csunicode11':
10659 case 'unicode11':
10660 return 'UNICODE-1-1';
10662 case 'csunicode11utf7':
10663 case 'unicode11utf7':
10664 return 'UNICODE-1-1-UTF-7';
10666 case 'csunknown8bit':
10667 case 'unknown8bit':
10668 return 'UNKNOWN-8BIT';
10670 case 'ansix341968':
10671 case 'ansix341986':
10672 case 'ascii':
10673 case 'cp367':
10674 case 'csascii':
10675 case 'ibm367':
10676 case 'iso646irv1991':
10677 case 'iso646us':
10678 case 'isoir6':
10679 case 'us':
10680 case 'usascii':
10681 return 'US-ASCII';
10683 case 'csusdk':
10684 case 'usdk':
10685 return 'us-dk';
10687 case 'utf7':
10688 return 'UTF-7';
10690 case 'utf8':
10691 return 'UTF-8';
10693 case 'utf16':
10694 return 'UTF-16';
10696 case 'utf16be':
10697 return 'UTF-16BE';
10699 case 'utf16le':
10700 return 'UTF-16LE';
10702 case 'utf32':
10703 return 'UTF-32';
10705 case 'utf32be':
10706 return 'UTF-32BE';
10708 case 'utf32le':
10709 return 'UTF-32LE';
10711 case 'csventurainternational':
10712 case 'venturainternational':
10713 return 'Ventura-International';
10715 case 'csventuramath':
10716 case 'venturamath':
10717 return 'Ventura-Math';
10719 case 'csventuraus':
10720 case 'venturaus':
10721 return 'Ventura-US';
10723 case 'csiso70videotexsupp1':
10724 case 'isoir70':
10725 case 'videotexsuppl':
10726 return 'videotex-suppl';
10728 case 'csviqr':
10729 case 'viqr':
10730 return 'VIQR';
10732 case 'csviscii':
10733 case 'viscii':
10734 return 'VISCII';
10736 case 'csshiftjis':
10737 case 'cswindows31j':
10738 case 'mskanji':
10739 case 'shiftjis':
10740 case 'windows31j':
10741 return 'Windows-31J';
10743 case 'iso885911':
10744 case 'tis620':
10745 return 'windows-874';
10747 case 'cseuckr':
10748 case 'csksc56011987':
10749 case 'euckr':
10750 case 'isoir149':
10751 case 'korean':
10752 case 'ksc5601':
10753 case 'ksc56011987':
10754 case 'ksc56011989':
10755 case 'windows949':
10756 return 'windows-949';
10758 case 'windows1250':
10759 return 'windows-1250';
10761 case 'windows1251':
10762 return 'windows-1251';
10764 case 'cp819':
10765 case 'csisolatin1':
10766 case 'ibm819':
10767 case 'iso88591':
10768 case 'iso885911987':
10769 case 'isoir100':
10770 case 'l1':
10771 case 'latin1':
10772 case 'windows1252':
10773 return 'windows-1252';
10775 case 'windows1253':
10776 return 'windows-1253';
10778 case 'csisolatin5':
10779 case 'iso88599':
10780 case 'iso885991989':
10781 case 'isoir148':
10782 case 'l5':
10783 case 'latin5':
10784 case 'windows1254':
10785 return 'windows-1254';
10787 case 'windows1255':
10788 return 'windows-1255';
10790 case 'windows1256':
10791 return 'windows-1256';
10793 case 'windows1257':
10794 return 'windows-1257';
10796 case 'windows1258':
10797 return 'windows-1258';
10799 default:
10800 return $charset;
10804 function get_curl_version()
10806 if (is_array($curl = curl_version()))
10808 $curl = $curl['version'];
10810 elseif (substr($curl, 0, 5) === 'curl/')
10812 $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
10814 elseif (substr($curl, 0, 8) === 'libcurl/')
10816 $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
10818 else
10820 $curl = 0;
10822 return $curl;
10825 function is_subclass_of($class1, $class2)
10827 if (func_num_args() !== 2)
10829 trigger_error('Wrong parameter count for SimplePie_Misc::is_subclass_of()', E_USER_WARNING);
10831 elseif (version_compare(PHP_VERSION, '5.0.3', '>=') || is_object($class1))
10833 return is_subclass_of($class1, $class2);
10835 elseif (is_string($class1) && is_string($class2))
10837 if (class_exists($class1))
10839 if (class_exists($class2))
10841 $class2 = strtolower($class2);
10842 while ($class1 = strtolower(get_parent_class($class1)))
10844 if ($class1 === $class2)
10846 return true;
10851 else
10853 trigger_error('Unknown class passed as parameter', E_USER_WARNNG);
10856 return false;
10860 * Strip HTML comments
10862 * @access public
10863 * @param string $data Data to strip comments from
10864 * @return string Comment stripped string
10866 function strip_comments($data)
10868 $output = '';
10869 while (($start = strpos($data, '<!--')) !== false)
10871 $output .= substr($data, 0, $start);
10872 if (($end = strpos($data, '-->', $start)) !== false)
10874 $data = substr_replace($data, '', 0, $end + 3);
10876 else
10878 $data = '';
10881 return $output . $data;
10884 function parse_date($dt)
10886 $parser = SimplePie_Parse_Date::get();
10887 return $parser->parse($dt);
10891 * Decode HTML entities
10893 * @static
10894 * @access public
10895 * @param string $data Input data
10896 * @return string Output data
10898 function entities_decode($data)
10900 $decoder = new SimplePie_Decode_HTML_Entities($data);
10901 return $decoder->parse();
10905 * Remove RFC822 comments
10907 * @access public
10908 * @param string $data Data to strip comments from
10909 * @return string Comment stripped string
10911 function uncomment_rfc822($string)
10913 $string = (string) $string;
10914 $position = 0;
10915 $length = strlen($string);
10916 $depth = 0;
10918 $output = '';
10920 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
10922 $output .= substr($string, $position, $pos - $position);
10923 $position = $pos + 1;
10924 if ($string[$pos - 1] !== '\\')
10926 $depth++;
10927 while ($depth && $position < $length)
10929 $position += strcspn($string, '()', $position);
10930 if ($string[$position - 1] === '\\')
10932 $position++;
10933 continue;
10935 elseif (isset($string[$position]))
10937 switch ($string[$position])
10939 case '(':
10940 $depth++;
10941 break;
10943 case ')':
10944 $depth--;
10945 break;
10947 $position++;
10949 else
10951 break;
10955 else
10957 $output .= '(';
10960 $output .= substr($string, $position);
10962 return $output;
10965 function parse_mime($mime)
10967 if (($pos = strpos($mime, ';')) === false)
10969 return trim($mime);
10971 else
10973 return trim(substr($mime, 0, $pos));
10977 function htmlspecialchars_decode($string, $quote_style)
10979 if (function_exists('htmlspecialchars_decode'))
10981 return htmlspecialchars_decode($string, $quote_style);
10983 else
10985 return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
10989 function atom_03_construct_type($attribs)
10991 if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64'))
10993 $mode = SIMPLEPIE_CONSTRUCT_BASE64;
10995 else
10997 $mode = SIMPLEPIE_CONSTRUCT_NONE;
10999 if (isset($attribs['']['type']))
11001 switch (strtolower(trim($attribs['']['type'])))
11003 case 'text':
11004 case 'text/plain':
11005 return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
11007 case 'html':
11008 case 'text/html':
11009 return SIMPLEPIE_CONSTRUCT_HTML | $mode;
11011 case 'xhtml':
11012 case 'application/xhtml+xml':
11013 return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
11015 default:
11016 return SIMPLEPIE_CONSTRUCT_NONE | $mode;
11019 else
11021 return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
11025 function atom_10_construct_type($attribs)
11027 if (isset($attribs['']['type']))
11029 switch (strtolower(trim($attribs['']['type'])))
11031 case 'text':
11032 return SIMPLEPIE_CONSTRUCT_TEXT;
11034 case 'html':
11035 return SIMPLEPIE_CONSTRUCT_HTML;
11037 case 'xhtml':
11038 return SIMPLEPIE_CONSTRUCT_XHTML;
11040 default:
11041 return SIMPLEPIE_CONSTRUCT_NONE;
11044 return SIMPLEPIE_CONSTRUCT_TEXT;
11047 function atom_10_content_construct_type($attribs)
11049 if (isset($attribs['']['type']))
11051 $type = strtolower(trim($attribs['']['type']));
11052 switch ($type)
11054 case 'text':
11055 return SIMPLEPIE_CONSTRUCT_TEXT;
11057 case 'html':
11058 return SIMPLEPIE_CONSTRUCT_HTML;
11060 case 'xhtml':
11061 return SIMPLEPIE_CONSTRUCT_XHTML;
11063 if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/')
11065 return SIMPLEPIE_CONSTRUCT_NONE;
11067 else
11069 return SIMPLEPIE_CONSTRUCT_BASE64;
11072 else
11074 return SIMPLEPIE_CONSTRUCT_TEXT;
11078 function is_isegment_nz_nc($string)
11080 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);
11083 function space_seperated_tokens($string)
11085 $space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
11086 $string_length = strlen($string);
11088 $position = strspn($string, $space_characters);
11089 $tokens = array();
11091 while ($position < $string_length)
11093 $len = strcspn($string, $space_characters, $position);
11094 $tokens[] = substr($string, $position, $len);
11095 $position += $len;
11096 $position += strspn($string, $space_characters, $position);
11099 return $tokens;
11102 function array_unique($array)
11104 if (version_compare(PHP_VERSION, '5.2', '>='))
11106 return array_unique($array);
11108 else
11110 $array = (array) $array;
11111 $new_array = array();
11112 $new_array_strings = array();
11113 foreach ($array as $key => $value)
11115 if (is_object($value))
11117 if (method_exists($value, '__toString'))
11119 $cmp = $value->__toString();
11121 else
11123 trigger_error('Object of class ' . get_class($value) . ' could not be converted to string', E_USER_ERROR);
11126 elseif (is_array($value))
11128 $cmp = (string) reset($value);
11130 else
11132 $cmp = (string) $value;
11134 if (!in_array($cmp, $new_array_strings))
11136 $new_array[$key] = $value;
11137 $new_array_strings[] = $cmp;
11140 return $new_array;
11145 * Converts a unicode codepoint to a UTF-8 character
11147 * @static
11148 * @access public
11149 * @param int $codepoint Unicode codepoint
11150 * @return string UTF-8 character
11152 function codepoint_to_utf8($codepoint)
11154 $codepoint = (int) $codepoint;
11155 if ($codepoint < 0)
11157 return false;
11159 else if ($codepoint <= 0x7f)
11161 return chr($codepoint);
11163 else if ($codepoint <= 0x7ff)
11165 return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
11167 else if ($codepoint <= 0xffff)
11169 return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
11171 else if ($codepoint <= 0x10ffff)
11173 return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
11175 else
11177 // U+FFFD REPLACEMENT CHARACTER
11178 return "\xEF\xBF\xBD";
11183 * Re-implementation of PHP 5's stripos()
11185 * Returns the numeric position of the first occurrence of needle in the
11186 * haystack string.
11188 * @static
11189 * @access string
11190 * @param object $haystack
11191 * @param string $needle Note that the needle may be a string of one or more
11192 * characters. If needle is not a string, it is converted to an integer
11193 * and applied as the ordinal value of a character.
11194 * @param int $offset The optional offset parameter allows you to specify which
11195 * character in haystack to start searching. The position returned is still
11196 * relative to the beginning of haystack.
11197 * @return bool If needle is not found, stripos() will return boolean false.
11199 function stripos($haystack, $needle, $offset = 0)
11201 if (function_exists('stripos'))
11203 return stripos($haystack, $needle, $offset);
11205 else
11207 if (is_string($needle))
11209 $needle = strtolower($needle);
11211 elseif (is_int($needle) || is_bool($needle) || is_double($needle))
11213 $needle = strtolower(chr($needle));
11215 else
11217 trigger_error('needle is not a string or an integer', E_USER_WARNING);
11218 return false;
11221 return strpos(strtolower($haystack), $needle, $offset);
11226 * Similar to parse_str()
11228 * Returns an associative array of name/value pairs, where the value is an
11229 * array of values that have used the same name
11231 * @static
11232 * @access string
11233 * @param string $str The input string.
11234 * @return array
11236 function parse_str($str)
11238 $return = array();
11239 $str = explode('&', $str);
11241 foreach ($str as $section)
11243 if (strpos($section, '=') !== false)
11245 list($name, $value) = explode('=', $section, 2);
11246 $return[urldecode($name)][] = urldecode($value);
11248 else
11250 $return[urldecode($section)][] = null;
11254 return $return;
11258 * Detect XML encoding, as per XML 1.0 Appendix F.1
11260 * @todo Add support for EBCDIC
11261 * @param string $data XML data
11262 * @return array Possible encodings
11264 function xml_encoding($data)
11266 // UTF-32 Big Endian BOM
11267 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
11269 $encoding[] = 'UTF-32BE';
11271 // UTF-32 Little Endian BOM
11272 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
11274 $encoding[] = 'UTF-32LE';
11276 // UTF-16 Big Endian BOM
11277 elseif (substr($data, 0, 2) === "\xFE\xFF")
11279 $encoding[] = 'UTF-16BE';
11281 // UTF-16 Little Endian BOM
11282 elseif (substr($data, 0, 2) === "\xFF\xFE")
11284 $encoding[] = 'UTF-16LE';
11286 // UTF-8 BOM
11287 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
11289 $encoding[] = 'UTF-8';
11291 // UTF-32 Big Endian Without BOM
11292 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")
11294 if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
11296 $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8'));
11297 if ($parser->parse())
11299 $encoding[] = $parser->encoding;
11302 $encoding[] = 'UTF-32BE';
11304 // UTF-32 Little Endian Without BOM
11305 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")
11307 if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
11309 $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8'));
11310 if ($parser->parse())
11312 $encoding[] = $parser->encoding;
11315 $encoding[] = 'UTF-32LE';
11317 // UTF-16 Big Endian Without BOM
11318 elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C")
11320 if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
11322 $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8'));
11323 if ($parser->parse())
11325 $encoding[] = $parser->encoding;
11328 $encoding[] = 'UTF-16BE';
11330 // UTF-16 Little Endian Without BOM
11331 elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00")
11333 if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
11335 $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8'));
11336 if ($parser->parse())
11338 $encoding[] = $parser->encoding;
11341 $encoding[] = 'UTF-16LE';
11343 // US-ASCII (or superset)
11344 elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C")
11346 if ($pos = strpos($data, "\x3F\x3E"))
11348 $parser = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
11349 if ($parser->parse())
11351 $encoding[] = $parser->encoding;
11354 $encoding[] = 'UTF-8';
11356 // Fallback to UTF-8
11357 else
11359 $encoding[] = 'UTF-8';
11361 return $encoding;
11364 function output_javascript()
11366 if (function_exists('ob_gzhandler'))
11368 ob_start('ob_gzhandler');
11370 header('Content-type: text/javascript; charset: UTF-8');
11371 header('Cache-Control: must-revalidate');
11372 header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
11374 function embed_odeo(link) {
11375 document.writeln('<embed src="http://odeo.com/flash/audio_player_fullsize.swf" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="440" height="80" wmode="transparent" allowScriptAccess="any" flashvars="valid_sample_rate=true&external_url='+link+'"></embed>');
11378 function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
11379 if (placeholder != '') {
11380 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>');
11382 else {
11383 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>');
11387 function embed_flash(bgcolor, width, height, link, loop, type) {
11388 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>');
11391 function embed_flv(width, height, link, placeholder, loop, player) {
11392 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>');
11395 function embed_wmedia(width, height, link) {
11396 document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
11398 <?php
11404 * Format debugging information
11406 function debug($sp)
11408 $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n";
11409 $info .= 'PHP ' . PHP_VERSION . "\n";
11410 if ($sp->error() !== null)
11412 $info .= 'Error occurred: ' . $sp->error() . "\n";
11414 else
11416 $info .= "No error found.\n";
11418 $info .= "Extensions:\n";
11419 $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml');
11420 foreach ($extensions as $ext)
11422 if (extension_loaded($ext))
11424 $info .= " $ext loaded\n";
11425 switch ($ext)
11427 case 'pcre':
11428 $info .= ' Version ' . PCRE_VERSION . "\n";
11429 break;
11430 case 'curl':
11431 $version = curl_version();
11432 $info .= ' Version ' . $version['version'] . "\n";
11433 break;
11434 case 'mbstring':
11435 $info .= ' Overloading: ' . mb_get_info('func_overload') . "\n";
11436 break;
11437 case 'iconv':
11438 $info .= ' Version ' . ICONV_VERSION . "\n";
11439 break;
11440 case 'xml':
11441 $info .= ' Version ' . LIBXML_DOTTED_VERSION . "\n";
11442 break;
11445 else
11447 $info .= " $ext not loaded\n";
11450 return $info;
11455 * Decode HTML Entities
11457 * This implements HTML5 as of revision 967 (2007-06-28)
11459 * @package SimplePie
11461 class SimplePie_Decode_HTML_Entities
11464 * Data to be parsed
11466 * @access private
11467 * @var string
11469 var $data = '';
11472 * Currently consumed bytes
11474 * @access private
11475 * @var string
11477 var $consumed = '';
11480 * Position of the current byte being parsed
11482 * @access private
11483 * @var int
11485 var $position = 0;
11488 * Create an instance of the class with the input data
11490 * @access public
11491 * @param string $data Input data
11493 function SimplePie_Decode_HTML_Entities($data)
11495 $this->data = $data;
11499 * Parse the input data
11501 * @access public
11502 * @return string Output data
11504 function parse()
11506 while (($this->position = strpos($this->data, '&', $this->position)) !== false)
11508 $this->consume();
11509 $this->entity();
11510 $this->consumed = '';
11512 return $this->data;
11516 * Consume the next byte
11518 * @access private
11519 * @return mixed The next byte, or false, if there is no more data
11521 function consume()
11523 if (isset($this->data[$this->position]))
11525 $this->consumed .= $this->data[$this->position];
11526 return $this->data[$this->position++];
11528 else
11530 return false;
11535 * Consume a range of characters
11537 * @access private
11538 * @param string $chars Characters to consume
11539 * @return mixed A series of characters that match the range, or false
11541 function consume_range($chars)
11543 if ($len = strspn($this->data, $chars, $this->position))
11545 $data = substr($this->data, $this->position, $len);
11546 $this->consumed .= $data;
11547 $this->position += $len;
11548 return $data;
11550 else
11552 return false;
11557 * Unconsume one byte
11559 * @access private
11561 function unconsume()
11563 $this->consumed = substr($this->consumed, 0, -1);
11564 $this->position--;
11568 * Decode an entity
11570 * @access private
11572 function entity()
11574 switch ($this->consume())
11576 case "\x09":
11577 case "\x0A":
11578 case "\x0B":
11579 case "\x0B":
11580 case "\x0C":
11581 case "\x20":
11582 case "\x3C":
11583 case "\x26":
11584 case false:
11585 break;
11587 case "\x23":
11588 switch ($this->consume())
11590 case "\x78":
11591 case "\x58":
11592 $range = '0123456789ABCDEFabcdef';
11593 $hex = true;
11594 break;
11596 default:
11597 $range = '0123456789';
11598 $hex = false;
11599 $this->unconsume();
11600 break;
11603 if ($codepoint = $this->consume_range($range))
11605 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");
11607 if ($hex)
11609 $codepoint = hexdec($codepoint);
11611 else
11613 $codepoint = intval($codepoint);
11616 if (isset($windows_1252_specials[$codepoint]))
11618 $replacement = $windows_1252_specials[$codepoint];
11620 else
11622 $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
11625 if (!in_array($this->consume(), array(';', false), true))
11627 $this->unconsume();
11630 $consumed_length = strlen($this->consumed);
11631 $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
11632 $this->position += strlen($replacement) - $consumed_length;
11634 break;
11636 default:
11637 static $entities = array('Aacute' => "\xC3\x81", 'aacute' => "\xC3\xA1", 'Aacute;' => "\xC3\x81", 'aacute;' => "\xC3\xA1", 'Acirc' => "\xC3\x82", 'acirc' => "\xC3\xA2", 'Acirc;' => "\xC3\x82", 'acirc;' => "\xC3\xA2", 'acute' => "\xC2\xB4", 'acute;' => "\xC2\xB4", 'AElig' => "\xC3\x86", 'aelig' => "\xC3\xA6", 'AElig;' => "\xC3\x86", 'aelig;' => "\xC3\xA6", 'Agrave' => "\xC3\x80", 'agrave' => "\xC3\xA0", 'Agrave;' => "\xC3\x80", 'agrave;' => "\xC3\xA0", 'alefsym;' => "\xE2\x84\xB5", 'Alpha;' => "\xCE\x91", 'alpha;' => "\xCE\xB1", 'AMP' => "\x26", 'amp' => "\x26", 'AMP;' => "\x26", 'amp;' => "\x26", 'and;' => "\xE2\x88\xA7", 'ang;' => "\xE2\x88\xA0", 'apos;' => "\x27", 'Aring' => "\xC3\x85", 'aring' => "\xC3\xA5", 'Aring;' => "\xC3\x85", 'aring;' => "\xC3\xA5", 'asymp;' => "\xE2\x89\x88", 'Atilde' => "\xC3\x83", 'atilde' => "\xC3\xA3", 'Atilde;' => "\xC3\x83", 'atilde;' => "\xC3\xA3", 'Auml' => "\xC3\x84", 'auml' => "\xC3\xA4", 'Auml;' => "\xC3\x84", 'auml;' => "\xC3\xA4", 'bdquo;' => "\xE2\x80\x9E", 'Beta;' => "\xCE\x92", 'beta;' => "\xCE\xB2", 'brvbar' => "\xC2\xA6", 'brvbar;' => "\xC2\xA6", 'bull;' => "\xE2\x80\xA2", 'cap;' => "\xE2\x88\xA9", 'Ccedil' => "\xC3\x87", 'ccedil' => "\xC3\xA7", 'Ccedil;' => "\xC3\x87", 'ccedil;' => "\xC3\xA7", 'cedil' => "\xC2\xB8", 'cedil;' => "\xC2\xB8", 'cent' => "\xC2\xA2", 'cent;' => "\xC2\xA2", 'Chi;' => "\xCE\xA7", 'chi;' => "\xCF\x87", 'circ;' => "\xCB\x86", 'clubs;' => "\xE2\x99\xA3", 'cong;' => "\xE2\x89\x85", 'COPY' => "\xC2\xA9", 'copy' => "\xC2\xA9", 'COPY;' => "\xC2\xA9", 'copy;' => "\xC2\xA9", 'crarr;' => "\xE2\x86\xB5", 'cup;' => "\xE2\x88\xAA", 'curren' => "\xC2\xA4", 'curren;' => "\xC2\xA4", 'Dagger;' => "\xE2\x80\xA1", 'dagger;' => "\xE2\x80\xA0", 'dArr;' => "\xE2\x87\x93", 'darr;' => "\xE2\x86\x93", 'deg' => "\xC2\xB0", 'deg;' => "\xC2\xB0", 'Delta;' => "\xCE\x94", 'delta;' => "\xCE\xB4", 'diams;' => "\xE2\x99\xA6", 'divide' => "\xC3\xB7", 'divide;' => "\xC3\xB7", 'Eacute' => "\xC3\x89", 'eacute' => "\xC3\xA9", 'Eacute;' => "\xC3\x89", 'eacute;' => "\xC3\xA9", 'Ecirc' => "\xC3\x8A", 'ecirc' => "\xC3\xAA", 'Ecirc;' => "\xC3\x8A", 'ecirc;' => "\xC3\xAA", 'Egrave' => "\xC3\x88", 'egrave' => "\xC3\xA8", 'Egrave;' => "\xC3\x88", 'egrave;' => "\xC3\xA8", 'empty;' => "\xE2\x88\x85", 'emsp;' => "\xE2\x80\x83", 'ensp;' => "\xE2\x80\x82", 'Epsilon;' => "\xCE\x95", 'epsilon;' => "\xCE\xB5", 'equiv;' => "\xE2\x89\xA1", 'Eta;' => "\xCE\x97", 'eta;' => "\xCE\xB7", 'ETH' => "\xC3\x90", 'eth' => "\xC3\xB0", 'ETH;' => "\xC3\x90", 'eth;' => "\xC3\xB0", 'Euml' => "\xC3\x8B", 'euml' => "\xC3\xAB", 'Euml;' => "\xC3\x8B", 'euml;' => "\xC3\xAB", 'euro;' => "\xE2\x82\xAC", 'exist;' => "\xE2\x88\x83", 'fnof;' => "\xC6\x92", 'forall;' => "\xE2\x88\x80", 'frac12' => "\xC2\xBD", 'frac12;' => "\xC2\xBD", 'frac14' => "\xC2\xBC", 'frac14;' => "\xC2\xBC", 'frac34' => "\xC2\xBE", 'frac34;' => "\xC2\xBE", 'frasl;' => "\xE2\x81\x84", 'Gamma;' => "\xCE\x93", 'gamma;' => "\xCE\xB3", 'ge;' => "\xE2\x89\xA5", 'GT' => "\x3E", 'gt' => "\x3E", 'GT;' => "\x3E", 'gt;' => "\x3E", 'hArr;' => "\xE2\x87\x94", 'harr;' => "\xE2\x86\x94", 'hearts;' => "\xE2\x99\xA5", 'hellip;' => "\xE2\x80\xA6", 'Iacute' => "\xC3\x8D", 'iacute' => "\xC3\xAD", 'Iacute;' => "\xC3\x8D", 'iacute;' => "\xC3\xAD", 'Icirc' => "\xC3\x8E", 'icirc' => "\xC3\xAE", 'Icirc;' => "\xC3\x8E", 'icirc;' => "\xC3\xAE", 'iexcl' => "\xC2\xA1", 'iexcl;' => "\xC2\xA1", 'Igrave' => "\xC3\x8C", 'igrave' => "\xC3\xAC", 'Igrave;' => "\xC3\x8C", 'igrave;' => "\xC3\xAC", 'image;' => "\xE2\x84\x91", 'infin;' => "\xE2\x88\x9E", 'int;' => "\xE2\x88\xAB", 'Iota;' => "\xCE\x99", 'iota;' => "\xCE\xB9", 'iquest' => "\xC2\xBF", 'iquest;' => "\xC2\xBF", 'isin;' => "\xE2\x88\x88", 'Iuml' => "\xC3\x8F", 'iuml' => "\xC3\xAF", 'Iuml;' => "\xC3\x8F", 'iuml;' => "\xC3\xAF", 'Kappa;' => "\xCE\x9A", 'kappa;' => "\xCE\xBA", 'Lambda;' => "\xCE\x9B", 'lambda;' => "\xCE\xBB", 'lang;' => "\xE3\x80\x88", 'laquo' => "\xC2\xAB", 'laquo;' => "\xC2\xAB", 'lArr;' => "\xE2\x87\x90", 'larr;' => "\xE2\x86\x90", 'lceil;' => "\xE2\x8C\x88", 'ldquo;' => "\xE2\x80\x9C", 'le;' => "\xE2\x89\xA4", 'lfloor;' => "\xE2\x8C\x8A", 'lowast;' => "\xE2\x88\x97", 'loz;' => "\xE2\x97\x8A", 'lrm;' => "\xE2\x80\x8E", 'lsaquo;' => "\xE2\x80\xB9", 'lsquo;' => "\xE2\x80\x98", 'LT' => "\x3C", 'lt' => "\x3C", 'LT;' => "\x3C", 'lt;' => "\x3C", 'macr' => "\xC2\xAF", 'macr;' => "\xC2\xAF", 'mdash;' => "\xE2\x80\x94", 'micro' => "\xC2\xB5", 'micro;' => "\xC2\xB5", 'middot' => "\xC2\xB7", 'middot;' => "\xC2\xB7", 'minus;' => "\xE2\x88\x92", 'Mu;' => "\xCE\x9C", 'mu;' => "\xCE\xBC", 'nabla;' => "\xE2\x88\x87", 'nbsp' => "\xC2\xA0", 'nbsp;' => "\xC2\xA0", 'ndash;' => "\xE2\x80\x93", 'ne;' => "\xE2\x89\xA0", 'ni;' => "\xE2\x88\x8B", 'not' => "\xC2\xAC", 'not;' => "\xC2\xAC", 'notin;' => "\xE2\x88\x89", 'nsub;' => "\xE2\x8A\x84", 'Ntilde' => "\xC3\x91", 'ntilde' => "\xC3\xB1", 'Ntilde;' => "\xC3\x91", 'ntilde;' => "\xC3\xB1", 'Nu;' => "\xCE\x9D", 'nu;' => "\xCE\xBD", 'Oacute' => "\xC3\x93", 'oacute' => "\xC3\xB3", 'Oacute;' => "\xC3\x93", 'oacute;' => "\xC3\xB3", 'Ocirc' => "\xC3\x94", 'ocirc' => "\xC3\xB4", 'Ocirc;' => "\xC3\x94", 'ocirc;' => "\xC3\xB4", 'OElig;' => "\xC5\x92", 'oelig;' => "\xC5\x93", 'Ograve' => "\xC3\x92", 'ograve' => "\xC3\xB2", 'Ograve;' => "\xC3\x92", 'ograve;' => "\xC3\xB2", 'oline;' => "\xE2\x80\xBE", 'Omega;' => "\xCE\xA9", 'omega;' => "\xCF\x89", 'Omicron;' => "\xCE\x9F", 'omicron;' => "\xCE\xBF", 'oplus;' => "\xE2\x8A\x95", 'or;' => "\xE2\x88\xA8", 'ordf' => "\xC2\xAA", 'ordf;' => "\xC2\xAA", 'ordm' => "\xC2\xBA", 'ordm;' => "\xC2\xBA", 'Oslash' => "\xC3\x98", 'oslash' => "\xC3\xB8", 'Oslash;' => "\xC3\x98", 'oslash;' => "\xC3\xB8", 'Otilde' => "\xC3\x95", 'otilde' => "\xC3\xB5", 'Otilde;' => "\xC3\x95", 'otilde;' => "\xC3\xB5", 'otimes;' => "\xE2\x8A\x97", 'Ouml' => "\xC3\x96", 'ouml' => "\xC3\xB6", 'Ouml;' => "\xC3\x96", 'ouml;' => "\xC3\xB6", 'para' => "\xC2\xB6", 'para;' => "\xC2\xB6", 'part;' => "\xE2\x88\x82", 'permil;' => "\xE2\x80\xB0", 'perp;' => "\xE2\x8A\xA5", 'Phi;' => "\xCE\xA6", 'phi;' => "\xCF\x86", 'Pi;' => "\xCE\xA0", 'pi;' => "\xCF\x80", 'piv;' => "\xCF\x96", 'plusmn' => "\xC2\xB1", 'plusmn;' => "\xC2\xB1", 'pound' => "\xC2\xA3", 'pound;' => "\xC2\xA3", 'Prime;' => "\xE2\x80\xB3", 'prime;' => "\xE2\x80\xB2", 'prod;' => "\xE2\x88\x8F", 'prop;' => "\xE2\x88\x9D", 'Psi;' => "\xCE\xA8", 'psi;' => "\xCF\x88", 'QUOT' => "\x22", 'quot' => "\x22", 'QUOT;' => "\x22", 'quot;' => "\x22", 'radic;' => "\xE2\x88\x9A", 'rang;' => "\xE3\x80\x89", 'raquo' => "\xC2\xBB", 'raquo;' => "\xC2\xBB", 'rArr;' => "\xE2\x87\x92", 'rarr;' => "\xE2\x86\x92", 'rceil;' => "\xE2\x8C\x89", 'rdquo;' => "\xE2\x80\x9D", 'real;' => "\xE2\x84\x9C", 'REG' => "\xC2\xAE", 'reg' => "\xC2\xAE", 'REG;' => "\xC2\xAE", 'reg;' => "\xC2\xAE", 'rfloor;' => "\xE2\x8C\x8B", 'Rho;' => "\xCE\xA1", 'rho;' => "\xCF\x81", 'rlm;' => "\xE2\x80\x8F", 'rsaquo;' => "\xE2\x80\xBA", 'rsquo;' => "\xE2\x80\x99", 'sbquo;' => "\xE2\x80\x9A", 'Scaron;' => "\xC5\xA0", 'scaron;' => "\xC5\xA1", 'sdot;' => "\xE2\x8B\x85", 'sect' => "\xC2\xA7", 'sect;' => "\xC2\xA7", 'shy' => "\xC2\xAD", 'shy;' => "\xC2\xAD", 'Sigma;' => "\xCE\xA3", 'sigma;' => "\xCF\x83", 'sigmaf;' => "\xCF\x82", 'sim;' => "\xE2\x88\xBC", 'spades;' => "\xE2\x99\xA0", 'sub;' => "\xE2\x8A\x82", 'sube;' => "\xE2\x8A\x86", 'sum;' => "\xE2\x88\x91", 'sup;' => "\xE2\x8A\x83", 'sup1' => "\xC2\xB9", 'sup1;' => "\xC2\xB9", 'sup2' => "\xC2\xB2", 'sup2;' => "\xC2\xB2", 'sup3' => "\xC2\xB3", 'sup3;' => "\xC2\xB3", 'supe;' => "\xE2\x8A\x87", 'szlig' => "\xC3\x9F", 'szlig;' => "\xC3\x9F", 'Tau;' => "\xCE\xA4", 'tau;' => "\xCF\x84", 'there4;' => "\xE2\x88\xB4", 'Theta;' => "\xCE\x98", 'theta;' => "\xCE\xB8", 'thetasym;' => "\xCF\x91", 'thinsp;' => "\xE2\x80\x89", 'THORN' => "\xC3\x9E", 'thorn' => "\xC3\xBE", 'THORN;' => "\xC3\x9E", 'thorn;' => "\xC3\xBE", 'tilde;' => "\xCB\x9C", 'times' => "\xC3\x97", 'times;' => "\xC3\x97", 'TRADE;' => "\xE2\x84\xA2", 'trade;' => "\xE2\x84\xA2", 'Uacute' => "\xC3\x9A", 'uacute' => "\xC3\xBA", 'Uacute;' => "\xC3\x9A", 'uacute;' => "\xC3\xBA", 'uArr;' => "\xE2\x87\x91", 'uarr;' => "\xE2\x86\x91", 'Ucirc' => "\xC3\x9B", 'ucirc' => "\xC3\xBB", 'Ucirc;' => "\xC3\x9B", 'ucirc;' => "\xC3\xBB", 'Ugrave' => "\xC3\x99", 'ugrave' => "\xC3\xB9", 'Ugrave;' => "\xC3\x99", 'ugrave;' => "\xC3\xB9", 'uml' => "\xC2\xA8", 'uml;' => "\xC2\xA8", 'upsih;' => "\xCF\x92", 'Upsilon;' => "\xCE\xA5", 'upsilon;' => "\xCF\x85", 'Uuml' => "\xC3\x9C", 'uuml' => "\xC3\xBC", 'Uuml;' => "\xC3\x9C", 'uuml;' => "\xC3\xBC", 'weierp;' => "\xE2\x84\x98", 'Xi;' => "\xCE\x9E", 'xi;' => "\xCE\xBE", 'Yacute' => "\xC3\x9D", 'yacute' => "\xC3\xBD", 'Yacute;' => "\xC3\x9D", 'yacute;' => "\xC3\xBD", 'yen' => "\xC2\xA5", 'yen;' => "\xC2\xA5", 'yuml' => "\xC3\xBF", 'Yuml;' => "\xC5\xB8", 'yuml;' => "\xC3\xBF", 'Zeta;' => "\xCE\x96", 'zeta;' => "\xCE\xB6", 'zwj;' => "\xE2\x80\x8D", 'zwnj;' => "\xE2\x80\x8C");
11639 for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
11641 $consumed = substr($this->consumed, 1);
11642 if (isset($entities[$consumed]))
11644 $match = $consumed;
11648 if ($match !== null)
11650 $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
11651 $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
11653 break;
11659 * IRI parser/serialiser
11661 * @package SimplePie
11663 class SimplePie_IRI
11666 * Scheme
11668 * @access private
11669 * @var string
11671 var $scheme;
11674 * User Information
11676 * @access private
11677 * @var string
11679 var $userinfo;
11682 * Host
11684 * @access private
11685 * @var string
11687 var $host;
11690 * Port
11692 * @access private
11693 * @var string
11695 var $port;
11698 * Path
11700 * @access private
11701 * @var string
11703 var $path;
11706 * Query
11708 * @access private
11709 * @var string
11711 var $query;
11714 * Fragment
11716 * @access private
11717 * @var string
11719 var $fragment;
11722 * Whether the object represents a valid IRI
11724 * @access private
11725 * @var array
11727 var $valid = array();
11730 * Return the entire IRI when you try and read the object as a string
11732 * @access public
11733 * @return string
11735 function __toString()
11737 return $this->get_iri();
11741 * Create a new IRI object, from a specified string
11743 * @access public
11744 * @param string $iri
11745 * @return SimplePie_IRI
11747 function SimplePie_IRI($iri)
11749 $iri = (string) $iri;
11750 if ($iri !== '')
11752 $parsed = $this->parse_iri($iri);
11753 $this->set_scheme($parsed['scheme']);
11754 $this->set_authority($parsed['authority']);
11755 $this->set_path($parsed['path']);
11756 $this->set_query($parsed['query']);
11757 $this->set_fragment($parsed['fragment']);
11762 * Create a new IRI object by resolving a relative IRI
11764 * @static
11765 * @access public
11766 * @param SimplePie_IRI $base Base IRI
11767 * @param string $relative Relative IRI
11768 * @return SimplePie_IRI
11770 function absolutize($base, $relative)
11772 $relative = (string) $relative;
11773 if ($relative !== '')
11775 $relative = new SimplePie_IRI($relative);
11776 if ($relative->get_scheme() !== null)
11778 $target = $relative;
11780 elseif ($base->get_iri() !== null)
11782 if ($relative->get_authority() !== null)
11784 $target = $relative;
11785 $target->set_scheme($base->get_scheme());
11787 else
11789 $target = new SimplePie_IRI('');
11790 $target->set_scheme($base->get_scheme());
11791 $target->set_userinfo($base->get_userinfo());
11792 $target->set_host($base->get_host());
11793 $target->set_port($base->get_port());
11794 if ($relative->get_path() !== null)
11796 if (strpos($relative->get_path(), '/') === 0)
11798 $target->set_path($relative->get_path());
11800 elseif (($base->get_userinfo() !== null || $base->get_host() !== null || $base->get_port() !== null) && $base->get_path() === null)
11802 $target->set_path('/' . $relative->get_path());
11804 elseif (($last_segment = strrpos($base->get_path(), '/')) !== false)
11806 $target->set_path(substr($base->get_path(), 0, $last_segment + 1) . $relative->get_path());
11808 else
11810 $target->set_path($relative->get_path());
11812 $target->set_query($relative->get_query());
11814 else
11816 $target->set_path($base->get_path());
11817 if ($relative->get_query() !== null)
11819 $target->set_query($relative->get_query());
11821 elseif ($base->get_query() !== null)
11823 $target->set_query($base->get_query());
11827 $target->set_fragment($relative->get_fragment());
11829 else
11831 // No base URL, just return the relative URL
11832 $target = $relative;
11835 else
11837 $target = $base;
11839 return $target;
11843 * Parse an IRI into scheme/authority/path/query/fragment segments
11845 * @access private
11846 * @param string $iri
11847 * @return array
11849 function parse_iri($iri)
11851 preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/', $iri, $match);
11852 for ($i = count($match); $i <= 9; $i++)
11854 $match[$i] = '';
11856 return array('scheme' => $match[2], 'authority' => $match[4], 'path' => $match[5], 'query' => $match[7], 'fragment' => $match[9]);
11860 * Remove dot segments from a path
11862 * @access private
11863 * @param string $input
11864 * @return string
11866 function remove_dot_segments($input)
11868 $output = '';
11869 while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
11871 // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
11872 if (strpos($input, '../') === 0)
11874 $input = substr($input, 3);
11876 elseif (strpos($input, './') === 0)
11878 $input = substr($input, 2);
11880 // 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,
11881 elseif (strpos($input, '/./') === 0)
11883 $input = substr_replace($input, '/', 0, 3);
11885 elseif ($input === '/.')
11887 $input = '/';
11889 // 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,
11890 elseif (strpos($input, '/../') === 0)
11892 $input = substr_replace($input, '/', 0, 4);
11893 $output = substr_replace($output, '', strrpos($output, '/'));
11895 elseif ($input === '/..')
11897 $input = '/';
11898 $output = substr_replace($output, '', strrpos($output, '/'));
11900 // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
11901 elseif ($input === '.' || $input === '..')
11903 $input = '';
11905 // 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
11906 elseif (($pos = strpos($input, '/', 1)) !== false)
11908 $output .= substr($input, 0, $pos);
11909 $input = substr_replace($input, '', 0, $pos);
11911 else
11913 $output .= $input;
11914 $input = '';
11917 return $output . $input;
11921 * Replace invalid character with percent encoding
11923 * @param string $string Input string
11924 * @param string $valid_chars Valid characters
11925 * @param int $case Normalise case
11926 * @return string
11928 function replace_invalid_with_pct_encoding($string, $valid_chars, $case = SIMPLEPIE_SAME_CASE, $iprivate = false)
11930 // Normalize as many pct-encoded sections as possible
11931 $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array(&$this, 'remove_iunreserved_percent_encoded'), $string);
11933 // Replace invalid percent characters
11934 $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
11936 // Add unreserved and % to $valid_chars (the latter is safe because all
11937 // pct-encoded sections are now valid).
11938 $valid_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
11940 // Now replace any bytes that aren't allowed with their pct-encoded versions
11941 $position = 0;
11942 $strlen = strlen($string);
11943 while (($position += strspn($string, $valid_chars, $position)) < $strlen)
11945 $value = ord($string[$position]);
11947 // Start position
11948 $start = $position;
11950 // By default we are valid
11951 $valid = true;
11953 // No one byte sequences are valid due to the while.
11954 // Two byte sequence:
11955 if (($value & 0xE0) === 0xC0)
11957 $character = ($value & 0x1F) << 6;
11958 $length = 2;
11959 $remaining = 1;
11961 // Three byte sequence:
11962 elseif (($value & 0xF0) === 0xE0)
11964 $character = ($value & 0x0F) << 12;
11965 $length = 3;
11966 $remaining = 2;
11968 // Four byte sequence:
11969 elseif (($value & 0xF8) === 0xF0)
11971 $character = ($value & 0x07) << 18;
11972 $length = 4;
11973 $remaining = 3;
11975 // Invalid byte:
11976 else
11978 $valid = false;
11979 $length = 1;
11980 $remaining = 0;
11983 if ($remaining)
11985 if ($position + $length <= $strlen)
11987 for ($position++; $remaining; $position++)
11989 $value = ord($string[$position]);
11991 // Check that the byte is valid, then add it to the character:
11992 if (($value & 0xC0) === 0x80)
11994 $character |= ($value & 0x3F) << (--$remaining * 6);
11996 // If it is invalid, count the sequence as invalid and reprocess the current byte:
11997 else
11999 $valid = false;
12000 $position--;
12001 break;
12005 else
12007 $position = $strlen - 1;
12008 $valid = false;
12012 // Percent encode anything invalid or not in ucschar
12013 if (
12014 // Invalid sequences
12015 !$valid
12016 // Non-shortest form sequences are invalid
12017 || $length > 1 && $character <= 0x7F
12018 || $length > 2 && $character <= 0x7FF
12019 || $length > 3 && $character <= 0xFFFF
12020 // Outside of range of ucschar codepoints
12021 // Noncharacters
12022 || ($character & 0xFFFE) === 0xFFFE
12023 || $character >= 0xFDD0 && $character <= 0xFDEF
12024 || (
12025 // Everything else not in ucschar
12026 $character > 0xD7FF && $character < 0xF900
12027 || $character < 0xA0
12028 || $character > 0xEFFFD
12030 && (
12031 // Everything not in iprivate, if it applies
12032 !$iprivate
12033 || $character < 0xE000
12034 || $character > 0x10FFFD
12038 // If we were a character, pretend we weren't, but rather an error.
12039 if ($valid)
12040 $position--;
12042 for ($j = $start; $j <= $position; $j++)
12044 $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
12045 $j += 2;
12046 $position += 2;
12047 $strlen += 2;
12052 // Normalise case
12053 if ($case & SIMPLEPIE_LOWERCASE)
12055 $string = strtolower($string);
12057 elseif ($case & SIMPLEPIE_UPPERCASE)
12059 $string = strtoupper($string);
12062 return $string;
12066 * Callback function for preg_replace_callback.
12068 * Removes sequences of percent encoded bytes that represent UTF-8
12069 * encoded characters in iunreserved
12071 * @access private
12072 * @param array $match PCRE match
12073 * @return string Replacement
12075 function remove_iunreserved_percent_encoded($match)
12077 // As we just have valid percent encoded sequences we can just explode
12078 // and ignore the first member of the returned array (an empty string).
12079 $bytes = explode('%', $match[0]);
12081 // Initialize the new string (this is what will be returned) and that
12082 // there are no bytes remaining in the current sequence (unsurprising
12083 // at the first byte!).
12084 $string = '';
12085 $remaining = 0;
12087 // Loop over each and every byte, and set $value to its value
12088 for ($i = 1, $len = count($bytes); $i < $len; $i++)
12090 $value = hexdec($bytes[$i]);
12092 // If we're the first byte of sequence:
12093 if (!$remaining)
12095 // Start position
12096 $start = $i;
12098 // By default we are valid
12099 $valid = true;
12101 // One byte sequence:
12102 if ($value <= 0x7F)
12104 $character = $value;
12105 $length = 1;
12107 // Two byte sequence:
12108 elseif (($value & 0xE0) === 0xC0)
12110 $character = ($value & 0x1F) << 6;
12111 $length = 2;
12112 $remaining = 1;
12114 // Three byte sequence:
12115 elseif (($value & 0xF0) === 0xE0)
12117 $character = ($value & 0x0F) << 12;
12118 $length = 3;
12119 $remaining = 2;
12121 // Four byte sequence:
12122 elseif (($value & 0xF8) === 0xF0)
12124 $character = ($value & 0x07) << 18;
12125 $length = 4;
12126 $remaining = 3;
12128 // Invalid byte:
12129 else
12131 $valid = false;
12132 $remaining = 0;
12135 // Continuation byte:
12136 else
12138 // Check that the byte is valid, then add it to the character:
12139 if (($value & 0xC0) === 0x80)
12141 $remaining--;
12142 $character |= ($value & 0x3F) << ($remaining * 6);
12144 // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
12145 else
12147 $valid = false;
12148 $remaining = 0;
12149 $i--;
12153 // If we've reached the end of the current byte sequence, append it to Unicode::$data
12154 if (!$remaining)
12156 // Percent encode anything invalid or not in iunreserved
12157 if (
12158 // Invalid sequences
12159 !$valid
12160 // Non-shortest form sequences are invalid
12161 || $length > 1 && $character <= 0x7F
12162 || $length > 2 && $character <= 0x7FF
12163 || $length > 3 && $character <= 0xFFFF
12164 // Outside of range of iunreserved codepoints
12165 || $character < 0x2D
12166 || $character > 0xEFFFD
12167 // Noncharacters
12168 || ($character & 0xFFFE) === 0xFFFE
12169 || $character >= 0xFDD0 && $character <= 0xFDEF
12170 // Everything else not in iunreserved (this is all BMP)
12171 || $character === 0x2F
12172 || $character > 0x39 && $character < 0x41
12173 || $character > 0x5A && $character < 0x61
12174 || $character > 0x7A && $character < 0x7E
12175 || $character > 0x7E && $character < 0xA0
12176 || $character > 0xD7FF && $character < 0xF900
12179 for ($j = $start; $j <= $i; $j++)
12181 $string .= '%' . strtoupper($bytes[$j]);
12184 else
12186 for ($j = $start; $j <= $i; $j++)
12188 $string .= chr(hexdec($bytes[$j]));
12194 // If we have any bytes left over they are invalid (i.e., we are
12195 // mid-way through a multi-byte sequence)
12196 if ($remaining)
12198 for ($j = $start; $j < $len; $j++)
12200 $string .= '%' . strtoupper($bytes[$j]);
12204 return $string;
12208 * Check if the object represents a valid IRI
12210 * @access public
12211 * @return bool
12213 function is_valid()
12215 return array_sum($this->valid) === count($this->valid);
12219 * Set the scheme. Returns true on success, false on failure (if there are
12220 * any invalid characters).
12222 * @access public
12223 * @param string $scheme
12224 * @return bool
12226 function set_scheme($scheme)
12228 if ($scheme === null || $scheme === '')
12230 $this->scheme = null;
12232 else
12234 $len = strlen($scheme);
12235 switch (true)
12237 case $len > 1:
12238 if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-.', 1))
12240 $this->scheme = null;
12241 $this->valid[__FUNCTION__] = false;
12242 return false;
12245 case $len > 0:
12246 if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 0, 1))
12248 $this->scheme = null;
12249 $this->valid[__FUNCTION__] = false;
12250 return false;
12253 $this->scheme = strtolower($scheme);
12255 $this->valid[__FUNCTION__] = true;
12256 return true;
12260 * Set the authority. Returns true on success, false on failure (if there are
12261 * any invalid characters).
12263 * @access public
12264 * @param string $authority
12265 * @return bool
12267 function set_authority($authority)
12269 if (($userinfo_end = strrpos($authority, '@')) !== false)
12271 $userinfo = substr($authority, 0, $userinfo_end);
12272 $authority = substr($authority, $userinfo_end + 1);
12274 else
12276 $userinfo = null;
12279 if (($port_start = strpos($authority, ':')) !== false)
12281 $port = substr($authority, $port_start + 1);
12282 $authority = substr($authority, 0, $port_start);
12284 else
12286 $port = null;
12289 return $this->set_userinfo($userinfo) && $this->set_host($authority) && $this->set_port($port);
12293 * Set the userinfo.
12295 * @access public
12296 * @param string $userinfo
12297 * @return bool
12299 function set_userinfo($userinfo)
12301 if ($userinfo === null || $userinfo === '')
12303 $this->userinfo = null;
12305 else
12307 $this->userinfo = $this->replace_invalid_with_pct_encoding($userinfo, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:');
12309 $this->valid[__FUNCTION__] = true;
12310 return true;
12314 * Set the host. Returns true on success, false on failure (if there are
12315 * any invalid characters).
12317 * @access public
12318 * @param string $host
12319 * @return bool
12321 function set_host($host)
12323 if ($host === null || $host === '')
12325 $this->host = null;
12326 $this->valid[__FUNCTION__] = true;
12327 return true;
12329 elseif ($host[0] === '[' && substr($host, -1) === ']')
12331 if (Net_IPv6::checkIPv6(substr($host, 1, -1)))
12333 $this->host = $host;
12334 $this->valid[__FUNCTION__] = true;
12335 return true;
12337 else
12339 $this->host = null;
12340 $this->valid[__FUNCTION__] = false;
12341 return false;
12344 else
12346 $this->host = $this->replace_invalid_with_pct_encoding($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=', SIMPLEPIE_LOWERCASE);
12347 $this->valid[__FUNCTION__] = true;
12348 return true;
12353 * Set the port. Returns true on success, false on failure (if there are
12354 * any invalid characters).
12356 * @access public
12357 * @param string $port
12358 * @return bool
12360 function set_port($port)
12362 if ($port === null || $port === '')
12364 $this->port = null;
12365 $this->valid[__FUNCTION__] = true;
12366 return true;
12368 elseif (strspn($port, '0123456789') === strlen($port))
12370 $this->port = (int) $port;
12371 $this->valid[__FUNCTION__] = true;
12372 return true;
12374 else
12376 $this->port = null;
12377 $this->valid[__FUNCTION__] = false;
12378 return false;
12383 * Set the path.
12385 * @access public
12386 * @param string $path
12387 * @return bool
12389 function set_path($path)
12391 if ($path === null || $path === '')
12393 $this->path = null;
12394 $this->valid[__FUNCTION__] = true;
12395 return true;
12397 elseif (substr($path, 0, 2) === '//' && $this->userinfo === null && $this->host === null && $this->port === null)
12399 $this->path = null;
12400 $this->valid[__FUNCTION__] = false;
12401 return false;
12403 else
12405 $this->path = $this->replace_invalid_with_pct_encoding($path, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=@/');
12406 if ($this->scheme !== null)
12408 $this->path = $this->remove_dot_segments($this->path);
12410 $this->valid[__FUNCTION__] = true;
12411 return true;
12416 * Set the query.
12418 * @access public
12419 * @param string $query
12420 * @return bool
12422 function set_query($query)
12424 if ($query === null || $query === '')
12426 $this->query = null;
12428 else
12430 $this->query = $this->replace_invalid_with_pct_encoding($query, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$\'()*+,;:@/?&=');
12432 $this->valid[__FUNCTION__] = true;
12433 return true;
12437 * Set the fragment.
12439 * @access public
12440 * @param string $fragment
12441 * @return bool
12443 function set_fragment($fragment)
12445 if ($fragment === null || $fragment === '')
12447 $this->fragment = null;
12449 else
12451 $this->fragment = $this->replace_invalid_with_pct_encoding($fragment, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:@/?');
12453 $this->valid[__FUNCTION__] = true;
12454 return true;
12458 * Get the complete IRI
12460 * @access public
12461 * @return string
12463 function get_iri()
12465 $iri = '';
12466 if ($this->scheme !== null)
12468 $iri .= $this->scheme . ':';
12470 if (($authority = $this->get_authority()) !== null)
12472 $iri .= '//' . $authority;
12474 if ($this->path !== null)
12476 $iri .= $this->path;
12478 if ($this->query !== null)
12480 $iri .= '?' . $this->query;
12482 if ($this->fragment !== null)
12484 $iri .= '#' . $this->fragment;
12487 if ($iri !== '')
12489 return $iri;
12491 else
12493 return null;
12498 * Get the scheme
12500 * @access public
12501 * @return string
12503 function get_scheme()
12505 return $this->scheme;
12509 * Get the complete authority
12511 * @access public
12512 * @return string
12514 function get_authority()
12516 $authority = '';
12517 if ($this->userinfo !== null)
12519 $authority .= $this->userinfo . '@';
12521 if ($this->host !== null)
12523 $authority .= $this->host;
12525 if ($this->port !== null)
12527 $authority .= ':' . $this->port;
12530 if ($authority !== '')
12532 return $authority;
12534 else
12536 return null;
12541 * Get the user information
12543 * @access public
12544 * @return string
12546 function get_userinfo()
12548 return $this->userinfo;
12552 * Get the host
12554 * @access public
12555 * @return string
12557 function get_host()
12559 return $this->host;
12563 * Get the port
12565 * @access public
12566 * @return string
12568 function get_port()
12570 return $this->port;
12574 * Get the path
12576 * @access public
12577 * @return string
12579 function get_path()
12581 return $this->path;
12585 * Get the query
12587 * @access public
12588 * @return string
12590 function get_query()
12592 return $this->query;
12596 * Get the fragment
12598 * @access public
12599 * @return string
12601 function get_fragment()
12603 return $this->fragment;
12608 * Class to validate and to work with IPv6 addresses.
12610 * @package SimplePie
12611 * @copyright 2003-2005 The PHP Group
12612 * @license http://www.opensource.org/licenses/bsd-license.php
12613 * @link http://pear.php.net/package/Net_IPv6
12614 * @author Alexander Merz <alexander.merz@web.de>
12615 * @author elfrink at introweb dot nl
12616 * @author Josh Peck <jmp at joshpeck dot org>
12617 * @author Geoffrey Sneddon <geoffers@gmail.com>
12619 class SimplePie_Net_IPv6
12622 * Removes a possible existing netmask specification of an IP address.
12624 * @param string $ip the (compressed) IP as Hex representation
12625 * @return string the IP the without netmask
12626 * @since 1.1.0
12627 * @access public
12628 * @static
12630 function removeNetmaskSpec($ip)
12632 if (strpos($ip, '/') !== false)
12634 list($addr, $nm) = explode('/', $ip);
12636 else
12638 $addr = $ip;
12640 return $addr;
12644 * Uncompresses an IPv6 address
12646 * RFC 2373 allows you to compress zeros in an address to '::'. This
12647 * function expects an valid IPv6 address and expands the '::' to
12648 * the required zeros.
12650 * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
12651 * ::1 -> 0:0:0:0:0:0:0:1
12653 * @access public
12654 * @static
12655 * @param string $ip a valid IPv6-address (hex format)
12656 * @return string the uncompressed IPv6-address (hex format)
12658 function Uncompress($ip)
12660 $uip = SimplePie_Net_IPv6::removeNetmaskSpec($ip);
12661 $c1 = -1;
12662 $c2 = -1;
12663 if (strpos($ip, '::') !== false)
12665 list($ip1, $ip2) = explode('::', $ip);
12666 if ($ip1 === '')
12668 $c1 = -1;
12670 else
12672 $pos = 0;
12673 if (($pos = substr_count($ip1, ':')) > 0)
12675 $c1 = $pos;
12677 else
12679 $c1 = 0;
12682 if ($ip2 === '')
12684 $c2 = -1;
12686 else
12688 $pos = 0;
12689 if (($pos = substr_count($ip2, ':')) > 0)
12691 $c2 = $pos;
12693 else
12695 $c2 = 0;
12698 if (strstr($ip2, '.'))
12700 $c2++;
12702 // ::
12703 if ($c1 === -1 && $c2 === -1)
12705 $uip = '0:0:0:0:0:0:0:0';
12707 // ::xxx
12708 else if ($c1 === -1)
12710 $fill = str_repeat('0:', 7 - $c2);
12711 $uip = str_replace('::', $fill, $uip);
12713 // xxx::
12714 else if ($c2 === -1)
12716 $fill = str_repeat(':0', 7 - $c1);
12717 $uip = str_replace('::', $fill, $uip);
12719 // xxx::xxx
12720 else
12722 $fill = str_repeat(':0:', 6 - $c2 - $c1);
12723 $uip = str_replace('::', $fill, $uip);
12724 $uip = str_replace('::', ':', $uip);
12727 return $uip;
12731 * Splits an IPv6 address into the IPv6 and a possible IPv4 part
12733 * RFC 2373 allows you to note the last two parts of an IPv6 address as
12734 * an IPv4 compatible address
12736 * Example: 0:0:0:0:0:0:13.1.68.3
12737 * 0:0:0:0:0:FFFF:129.144.52.38
12739 * @access public
12740 * @static
12741 * @param string $ip a valid IPv6-address (hex format)
12742 * @return array [0] contains the IPv6 part, [1] the IPv4 part (hex format)
12744 function SplitV64($ip)
12746 $ip = SimplePie_Net_IPv6::Uncompress($ip);
12747 if (strstr($ip, '.'))
12749 $pos = strrpos($ip, ':');
12750 $ip[$pos] = '_';
12751 $ipPart = explode('_', $ip);
12752 return $ipPart;
12754 else
12756 return array($ip, '');
12761 * Checks an IPv6 address
12763 * Checks if the given IP is IPv6-compatible
12765 * @access public
12766 * @static
12767 * @param string $ip a valid IPv6-address
12768 * @return bool true if $ip is an IPv6 address
12770 function checkIPv6($ip)
12772 $ipPart = SimplePie_Net_IPv6::SplitV64($ip);
12773 $count = 0;
12774 if (!empty($ipPart[0]))
12776 $ipv6 = explode(':', $ipPart[0]);
12777 for ($i = 0; $i < count($ipv6); $i++)
12779 $dec = hexdec($ipv6[$i]);
12780 $hex = strtoupper(preg_replace('/^[0]{1,3}(.*[0-9a-fA-F])$/', '\\1', $ipv6[$i]));
12781 if ($ipv6[$i] >= 0 && $dec <= 65535 && $hex === strtoupper(dechex($dec)))
12783 $count++;
12786 if ($count === 8)
12788 return true;
12790 elseif ($count === 6 && !empty($ipPart[1]))
12792 $ipv4 = explode('.', $ipPart[1]);
12793 $count = 0;
12794 foreach ($ipv4 as $ipv4_part)
12796 if ($ipv4_part >= 0 && $ipv4_part <= 255 && preg_match('/^\d{1,3}$/', $ipv4_part))
12798 $count++;
12801 if ($count === 4)
12803 return true;
12806 else
12808 return false;
12812 else
12814 return false;
12820 * Date Parser
12822 * @package SimplePie
12824 class SimplePie_Parse_Date
12827 * Input data
12829 * @access protected
12830 * @var string
12832 var $date;
12835 * List of days, calendar day name => ordinal day number in the week
12837 * @access protected
12838 * @var array
12840 var $day = array(
12841 // English
12842 'mon' => 1,
12843 'monday' => 1,
12844 'tue' => 2,
12845 'tuesday' => 2,
12846 'wed' => 3,
12847 'wednesday' => 3,
12848 'thu' => 4,
12849 'thursday' => 4,
12850 'fri' => 5,
12851 'friday' => 5,
12852 'sat' => 6,
12853 'saturday' => 6,
12854 'sun' => 7,
12855 'sunday' => 7,
12856 // Dutch
12857 'maandag' => 1,
12858 'dinsdag' => 2,
12859 'woensdag' => 3,
12860 'donderdag' => 4,
12861 'vrijdag' => 5,
12862 'zaterdag' => 6,
12863 'zondag' => 7,
12864 // French
12865 'lundi' => 1,
12866 'mardi' => 2,
12867 'mercredi' => 3,
12868 'jeudi' => 4,
12869 'vendredi' => 5,
12870 'samedi' => 6,
12871 'dimanche' => 7,
12872 // German
12873 'montag' => 1,
12874 'dienstag' => 2,
12875 'mittwoch' => 3,
12876 'donnerstag' => 4,
12877 'freitag' => 5,
12878 'samstag' => 6,
12879 'sonnabend' => 6,
12880 'sonntag' => 7,
12881 // Italian
12882 'lunedì' => 1,
12883 'martedì' => 2,
12884 'mercoledì' => 3,
12885 'giovedì' => 4,
12886 'venerdì' => 5,
12887 'sabato' => 6,
12888 'domenica' => 7,
12889 // Spanish
12890 'lunes' => 1,
12891 'martes' => 2,
12892 'miércoles' => 3,
12893 'jueves' => 4,
12894 'viernes' => 5,
12895 'sábado' => 6,
12896 'domingo' => 7,
12897 // Finnish
12898 'maanantai' => 1,
12899 'tiistai' => 2,
12900 'keskiviikko' => 3,
12901 'torstai' => 4,
12902 'perjantai' => 5,
12903 'lauantai' => 6,
12904 'sunnuntai' => 7,
12905 // Hungarian
12906 'hétfő' => 1,
12907 'kedd' => 2,
12908 'szerda' => 3,
12909 'csütörtok' => 4,
12910 'péntek' => 5,
12911 'szombat' => 6,
12912 'vasárnap' => 7,
12913 // Greek
12914 'Δευ' => 1,
12915 'Τρι' => 2,
12916 'Τετ' => 3,
12917 'Πεμ' => 4,
12918 'Παρ' => 5,
12919 'Σαβ' => 6,
12920 'Κυρ' => 7,
12924 * List of months, calendar month name => calendar month number
12926 * @access protected
12927 * @var array
12929 var $month = array(
12930 // English
12931 'jan' => 1,
12932 'january' => 1,
12933 'feb' => 2,
12934 'february' => 2,
12935 'mar' => 3,
12936 'march' => 3,
12937 'apr' => 4,
12938 'april' => 4,
12939 'may' => 5,
12940 // No long form of May
12941 'jun' => 6,
12942 'june' => 6,
12943 'jul' => 7,
12944 'july' => 7,
12945 'aug' => 8,
12946 'august' => 8,
12947 'sep' => 9,
12948 'september' => 8,
12949 'oct' => 10,
12950 'october' => 10,
12951 'nov' => 11,
12952 'november' => 11,
12953 'dec' => 12,
12954 'december' => 12,
12955 // Dutch
12956 'januari' => 1,
12957 'februari' => 2,
12958 'maart' => 3,
12959 'april' => 4,
12960 'mei' => 5,
12961 'juni' => 6,
12962 'juli' => 7,
12963 'augustus' => 8,
12964 'september' => 9,
12965 'oktober' => 10,
12966 'november' => 11,
12967 'december' => 12,
12968 // French
12969 'janvier' => 1,
12970 'février' => 2,
12971 'mars' => 3,
12972 'avril' => 4,
12973 'mai' => 5,
12974 'juin' => 6,
12975 'juillet' => 7,
12976 'août' => 8,
12977 'septembre' => 9,
12978 'octobre' => 10,
12979 'novembre' => 11,
12980 'décembre' => 12,
12981 // German
12982 'januar' => 1,
12983 'februar' => 2,
12984 'märz' => 3,
12985 'april' => 4,
12986 'mai' => 5,
12987 'juni' => 6,
12988 'juli' => 7,
12989 'august' => 8,
12990 'september' => 9,
12991 'oktober' => 10,
12992 'november' => 11,
12993 'dezember' => 12,
12994 // Italian
12995 'gennaio' => 1,
12996 'febbraio' => 2,
12997 'marzo' => 3,
12998 'aprile' => 4,
12999 'maggio' => 5,
13000 'giugno' => 6,
13001 'luglio' => 7,
13002 'agosto' => 8,
13003 'settembre' => 9,
13004 'ottobre' => 10,
13005 'novembre' => 11,
13006 'dicembre' => 12,
13007 // Spanish
13008 'enero' => 1,
13009 'febrero' => 2,
13010 'marzo' => 3,
13011 'abril' => 4,
13012 'mayo' => 5,
13013 'junio' => 6,
13014 'julio' => 7,
13015 'agosto' => 8,
13016 'septiembre' => 9,
13017 'setiembre' => 9,
13018 'octubre' => 10,
13019 'noviembre' => 11,
13020 'diciembre' => 12,
13021 // Finnish
13022 'tammikuu' => 1,
13023 'helmikuu' => 2,
13024 'maaliskuu' => 3,
13025 'huhtikuu' => 4,
13026 'toukokuu' => 5,
13027 'kesäkuu' => 6,
13028 'heinäkuu' => 7,
13029 'elokuu' => 8,
13030 'suuskuu' => 9,
13031 'lokakuu' => 10,
13032 'marras' => 11,
13033 'joulukuu' => 12,
13034 // Hungarian
13035 'január' => 1,
13036 'február' => 2,
13037 'március' => 3,
13038 'április' => 4,
13039 'május' => 5,
13040 'június' => 6,
13041 'július' => 7,
13042 'augusztus' => 8,
13043 'szeptember' => 9,
13044 'október' => 10,
13045 'november' => 11,
13046 'december' => 12,
13047 // Greek
13048 'Ιαν' => 1,
13049 'Φεβ' => 2,
13050 'Μάώ' => 3,
13051 'Μαώ' => 3,
13052 'Απρ' => 4,
13053 'Μάι' => 5,
13054 'Μαϊ' => 5,
13055 'Μαι' => 5,
13056 'Ιούν' => 6,
13057 'Ιον' => 6,
13058 'Ιούλ' => 7,
13059 'Ιολ' => 7,
13060 'Αύγ' => 8,
13061 'Αυγ' => 8,
13062 'Σεπ' => 9,
13063 'Οκτ' => 10,
13064 'Νοέ' => 11,
13065 'Δεκ' => 12,
13069 * List of timezones, abbreviation => offset from UTC
13071 * @access protected
13072 * @var array
13074 var $timezone = array(
13075 'ACDT' => 37800,
13076 'ACIT' => 28800,
13077 'ACST' => 34200,
13078 'ACT' => -18000,
13079 'ACWDT' => 35100,
13080 'ACWST' => 31500,
13081 'AEDT' => 39600,
13082 'AEST' => 36000,
13083 'AFT' => 16200,
13084 'AKDT' => -28800,
13085 'AKST' => -32400,
13086 'AMDT' => 18000,
13087 'AMT' => -14400,
13088 'ANAST' => 46800,
13089 'ANAT' => 43200,
13090 'ART' => -10800,
13091 'AZOST' => -3600,
13092 'AZST' => 18000,
13093 'AZT' => 14400,
13094 'BIOT' => 21600,
13095 'BIT' => -43200,
13096 'BOT' => -14400,
13097 'BRST' => -7200,
13098 'BRT' => -10800,
13099 'BST' => 3600,
13100 'BTT' => 21600,
13101 'CAST' => 18000,
13102 'CAT' => 7200,
13103 'CCT' => 23400,
13104 'CDT' => -18000,
13105 'CEDT' => 7200,
13106 'CET' => 3600,
13107 'CGST' => -7200,
13108 'CGT' => -10800,
13109 'CHADT' => 49500,
13110 'CHAST' => 45900,
13111 'CIST' => -28800,
13112 'CKT' => -36000,
13113 'CLDT' => -10800,
13114 'CLST' => -14400,
13115 'COT' => -18000,
13116 'CST' => -21600,
13117 'CVT' => -3600,
13118 'CXT' => 25200,
13119 'DAVT' => 25200,
13120 'DTAT' => 36000,
13121 'EADT' => -18000,
13122 'EAST' => -21600,
13123 'EAT' => 10800,
13124 'ECT' => -18000,
13125 'EDT' => -14400,
13126 'EEST' => 10800,
13127 'EET' => 7200,
13128 'EGT' => -3600,
13129 'EKST' => 21600,
13130 'EST' => -18000,
13131 'FJT' => 43200,
13132 'FKDT' => -10800,
13133 'FKST' => -14400,
13134 'FNT' => -7200,
13135 'GALT' => -21600,
13136 'GEDT' => 14400,
13137 'GEST' => 10800,
13138 'GFT' => -10800,
13139 'GILT' => 43200,
13140 'GIT' => -32400,
13141 'GST' => 14400,
13142 'GST' => -7200,
13143 'GYT' => -14400,
13144 'HAA' => -10800,
13145 'HAC' => -18000,
13146 'HADT' => -32400,
13147 'HAE' => -14400,
13148 'HAP' => -25200,
13149 'HAR' => -21600,
13150 'HAST' => -36000,
13151 'HAT' => -9000,
13152 'HAY' => -28800,
13153 'HKST' => 28800,
13154 'HMT' => 18000,
13155 'HNA' => -14400,
13156 'HNC' => -21600,
13157 'HNE' => -18000,
13158 'HNP' => -28800,
13159 'HNR' => -25200,
13160 'HNT' => -12600,
13161 'HNY' => -32400,
13162 'IRDT' => 16200,
13163 'IRKST' => 32400,
13164 'IRKT' => 28800,
13165 'IRST' => 12600,
13166 'JFDT' => -10800,
13167 'JFST' => -14400,
13168 'JST' => 32400,
13169 'KGST' => 21600,
13170 'KGT' => 18000,
13171 'KOST' => 39600,
13172 'KOVST' => 28800,
13173 'KOVT' => 25200,
13174 'KRAST' => 28800,
13175 'KRAT' => 25200,
13176 'KST' => 32400,
13177 'LHDT' => 39600,
13178 'LHST' => 37800,
13179 'LINT' => 50400,
13180 'LKT' => 21600,
13181 'MAGST' => 43200,
13182 'MAGT' => 39600,
13183 'MAWT' => 21600,
13184 'MDT' => -21600,
13185 'MESZ' => 7200,
13186 'MEZ' => 3600,
13187 'MHT' => 43200,
13188 'MIT' => -34200,
13189 'MNST' => 32400,
13190 'MSDT' => 14400,
13191 'MSST' => 10800,
13192 'MST' => -25200,
13193 'MUT' => 14400,
13194 'MVT' => 18000,
13195 'MYT' => 28800,
13196 'NCT' => 39600,
13197 'NDT' => -9000,
13198 'NFT' => 41400,
13199 'NMIT' => 36000,
13200 'NOVST' => 25200,
13201 'NOVT' => 21600,
13202 'NPT' => 20700,
13203 'NRT' => 43200,
13204 'NST' => -12600,
13205 'NUT' => -39600,
13206 'NZDT' => 46800,
13207 'NZST' => 43200,
13208 'OMSST' => 25200,
13209 'OMST' => 21600,
13210 'PDT' => -25200,
13211 'PET' => -18000,
13212 'PETST' => 46800,
13213 'PETT' => 43200,
13214 'PGT' => 36000,
13215 'PHOT' => 46800,
13216 'PHT' => 28800,
13217 'PKT' => 18000,
13218 'PMDT' => -7200,
13219 'PMST' => -10800,
13220 'PONT' => 39600,
13221 'PST' => -28800,
13222 'PWT' => 32400,
13223 'PYST' => -10800,
13224 'PYT' => -14400,
13225 'RET' => 14400,
13226 'ROTT' => -10800,
13227 'SAMST' => 18000,
13228 'SAMT' => 14400,
13229 'SAST' => 7200,
13230 'SBT' => 39600,
13231 'SCDT' => 46800,
13232 'SCST' => 43200,
13233 'SCT' => 14400,
13234 'SEST' => 3600,
13235 'SGT' => 28800,
13236 'SIT' => 28800,
13237 'SRT' => -10800,
13238 'SST' => -39600,
13239 'SYST' => 10800,
13240 'SYT' => 7200,
13241 'TFT' => 18000,
13242 'THAT' => -36000,
13243 'TJT' => 18000,
13244 'TKT' => -36000,
13245 'TMT' => 18000,
13246 'TOT' => 46800,
13247 'TPT' => 32400,
13248 'TRUT' => 36000,
13249 'TVT' => 43200,
13250 'TWT' => 28800,
13251 'UYST' => -7200,
13252 'UYT' => -10800,
13253 'UZT' => 18000,
13254 'VET' => -14400,
13255 'VLAST' => 39600,
13256 'VLAT' => 36000,
13257 'VOST' => 21600,
13258 'VUT' => 39600,
13259 'WAST' => 7200,
13260 'WAT' => 3600,
13261 'WDT' => 32400,
13262 'WEST' => 3600,
13263 'WFT' => 43200,
13264 'WIB' => 25200,
13265 'WIT' => 32400,
13266 'WITA' => 28800,
13267 'WKST' => 18000,
13268 'WST' => 28800,
13269 'YAKST' => 36000,
13270 'YAKT' => 32400,
13271 'YAPT' => 36000,
13272 'YEKST' => 21600,
13273 'YEKT' => 18000,
13277 * Cached PCRE for SimplePie_Parse_Date::$day
13279 * @access protected
13280 * @var string
13282 var $day_pcre;
13285 * Cached PCRE for SimplePie_Parse_Date::$month
13287 * @access protected
13288 * @var string
13290 var $month_pcre;
13293 * Array of user-added callback methods
13295 * @access private
13296 * @var array
13298 var $built_in = array();
13301 * Array of user-added callback methods
13303 * @access private
13304 * @var array
13306 var $user = array();
13309 * Create new SimplePie_Parse_Date object, and set self::day_pcre,
13310 * self::month_pcre, and self::built_in
13312 * @access private
13314 function SimplePie_Parse_Date()
13316 $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
13317 $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
13319 static $cache;
13320 if (!isset($cache[get_class($this)]))
13322 $all_methods = get_class_methods($this);
13324 foreach ($all_methods as $method)
13326 if (strtolower(substr($method, 0, 5)) === 'date_')
13328 $cache[get_class($this)][] = $method;
13333 foreach ($cache[get_class($this)] as $method)
13335 $this->built_in[] = $method;
13340 * Get the object
13342 * @access public
13344 function get()
13346 static $object;
13347 if (!$object)
13349 $object = new SimplePie_Parse_Date;
13351 return $object;
13355 * Parse a date
13357 * @final
13358 * @access public
13359 * @param string $date Date to parse
13360 * @return int Timestamp corresponding to date string, or false on failure
13362 function parse($date)
13364 foreach ($this->user as $method)
13366 if (($returned = call_user_func($method, $date)) !== false)
13368 return $returned;
13372 foreach ($this->built_in as $method)
13374 if (($returned = call_user_func(array(&$this, $method), $date)) !== false)
13376 return $returned;
13380 return false;
13384 * Add a callback method to parse a date
13386 * @final
13387 * @access public
13388 * @param callback $callback
13390 function add_callback($callback)
13392 if (is_callable($callback))
13394 $this->user[] = $callback;
13396 else
13398 trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
13403 * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
13404 * well as allowing any of upper or lower case "T", horizontal tabs, or
13405 * spaces to be used as the time seperator (including more than one))
13407 * @access protected
13408 * @return int Timestamp
13410 function date_w3cdtf($date)
13412 static $pcre;
13413 if (!$pcre)
13415 $year = '([0-9]{4})';
13416 $month = $day = $hour = $minute = $second = '([0-9]{2})';
13417 $decimal = '([0-9]*)';
13418 $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
13419 $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
13421 if (preg_match($pcre, $date, $match))
13424 Capturing subpatterns:
13425 1: Year
13426 2: Month
13427 3: Day
13428 4: Hour
13429 5: Minute
13430 6: Second
13431 7: Decimal fraction of a second
13432 8: Zulu
13433 9: Timezone ±
13434 10: Timezone hours
13435 11: Timezone minutes
13438 // Fill in empty matches
13439 for ($i = count($match); $i <= 3; $i++)
13441 $match[$i] = '1';
13444 for ($i = count($match); $i <= 7; $i++)
13446 $match[$i] = '0';
13449 // Numeric timezone
13450 if (isset($match[9]) && $match[9] !== '')
13452 $timezone = $match[10] * 3600;
13453 $timezone += $match[11] * 60;
13454 if ($match[9] === '-')
13456 $timezone = 0 - $timezone;
13459 else
13461 $timezone = 0;
13464 // Convert the number of seconds to an integer, taking decimals into account
13465 $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
13467 return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
13469 else
13471 return false;
13476 * Remove RFC822 comments
13478 * @access protected
13479 * @param string $data Data to strip comments from
13480 * @return string Comment stripped string
13482 function remove_rfc2822_comments($string)
13484 $string = (string) $string;
13485 $position = 0;
13486 $length = strlen($string);
13487 $depth = 0;
13489 $output = '';
13491 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
13493 $output .= substr($string, $position, $pos - $position);
13494 $position = $pos + 1;
13495 if ($string[$pos - 1] !== '\\')
13497 $depth++;
13498 while ($depth && $position < $length)
13500 $position += strcspn($string, '()', $position);
13501 if ($string[$position - 1] === '\\')
13503 $position++;
13504 continue;
13506 elseif (isset($string[$position]))
13508 switch ($string[$position])
13510 case '(':
13511 $depth++;
13512 break;
13514 case ')':
13515 $depth--;
13516 break;
13518 $position++;
13520 else
13522 break;
13526 else
13528 $output .= '(';
13531 $output .= substr($string, $position);
13533 return $output;
13537 * Parse RFC2822's date format
13539 * @access protected
13540 * @return int Timestamp
13542 function date_rfc2822($date)
13544 static $pcre;
13545 if (!$pcre)
13547 $wsp = '[\x09\x20]';
13548 $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
13549 $optional_fws = $fws . '?';
13550 $day_name = $this->day_pcre;
13551 $month = $this->month_pcre;
13552 $day = '([0-9]{1,2})';
13553 $hour = $minute = $second = '([0-9]{2})';
13554 $year = '([0-9]{2,4})';
13555 $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
13556 $character_zone = '([A-Z]{1,5})';
13557 $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
13558 $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';
13560 if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
13563 Capturing subpatterns:
13564 1: Day name
13565 2: Day
13566 3: Month
13567 4: Year
13568 5: Hour
13569 6: Minute
13570 7: Second
13571 8: Timezone ±
13572 9: Timezone hours
13573 10: Timezone minutes
13574 11: Alphabetic timezone
13577 // Find the month number
13578 $month = $this->month[strtolower($match[3])];
13580 // Numeric timezone
13581 if ($match[8] !== '')
13583 $timezone = $match[9] * 3600;
13584 $timezone += $match[10] * 60;
13585 if ($match[8] === '-')
13587 $timezone = 0 - $timezone;
13590 // Character timezone
13591 elseif (isset($this->timezone[strtoupper($match[11])]))
13593 $timezone = $this->timezone[strtoupper($match[11])];
13595 // Assume everything else to be -0000
13596 else
13598 $timezone = 0;
13601 // Deal with 2/3 digit years
13602 if ($match[4] < 50)
13604 $match[4] += 2000;
13606 elseif ($match[4] < 1000)
13608 $match[4] += 1900;
13611 // Second is optional, if it is empty set it to zero
13612 if ($match[7] !== '')
13614 $second = $match[7];
13616 else
13618 $second = 0;
13621 return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
13623 else
13625 return false;
13630 * Parse RFC850's date format
13632 * @access protected
13633 * @return int Timestamp
13635 function date_rfc850($date)
13637 static $pcre;
13638 if (!$pcre)
13640 $space = '[\x09\x20]+';
13641 $day_name = $this->day_pcre;
13642 $month = $this->month_pcre;
13643 $day = '([0-9]{1,2})';
13644 $year = $hour = $minute = $second = '([0-9]{2})';
13645 $zone = '([A-Z]{1,5})';
13646 $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
13648 if (preg_match($pcre, $date, $match))
13651 Capturing subpatterns:
13652 1: Day name
13653 2: Day
13654 3: Month
13655 4: Year
13656 5: Hour
13657 6: Minute
13658 7: Second
13659 8: Timezone
13662 // Month
13663 $month = $this->month[strtolower($match[3])];
13665 // Character timezone
13666 if (isset($this->timezone[strtoupper($match[8])]))
13668 $timezone = $this->timezone[strtoupper($match[8])];
13670 // Assume everything else to be -0000
13671 else
13673 $timezone = 0;
13676 // Deal with 2 digit year
13677 if ($match[4] < 50)
13679 $match[4] += 2000;
13681 else
13683 $match[4] += 1900;
13686 return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
13688 else
13690 return false;
13695 * Parse C99's asctime()'s date format
13697 * @access protected
13698 * @return int Timestamp
13700 function date_asctime($date)
13702 static $pcre;
13703 if (!$pcre)
13705 $space = '[\x09\x20]+';
13706 $wday_name = $this->day_pcre;
13707 $mon_name = $this->month_pcre;
13708 $day = '([0-9]{1,2})';
13709 $hour = $sec = $min = '([0-9]{2})';
13710 $year = '([0-9]{4})';
13711 $terminator = '\x0A?\x00?';
13712 $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
13714 if (preg_match($pcre, $date, $match))
13717 Capturing subpatterns:
13718 1: Day name
13719 2: Month
13720 3: Day
13721 4: Hour
13722 5: Minute
13723 6: Second
13724 7: Year
13727 $month = $this->month[strtolower($match[2])];
13728 return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
13730 else
13732 return false;
13737 * Parse dates using strtotime()
13739 * @access protected
13740 * @return int Timestamp
13742 function date_strtotime($date)
13744 $strtotime = strtotime($date);
13745 if ($strtotime === -1 || $strtotime === false)
13747 return false;
13749 else
13751 return $strtotime;
13757 * Content-type sniffing
13759 * @package SimplePie
13761 class SimplePie_Content_Type_Sniffer
13764 * File object
13766 * @var SimplePie_File
13767 * @access private
13769 var $file;
13772 * Create an instance of the class with the input file
13774 * @access public
13775 * @param SimplePie_Content_Type_Sniffer $file Input file
13777 function SimplePie_Content_Type_Sniffer($file)
13779 $this->file = $file;
13783 * Get the Content-Type of the specified file
13785 * @access public
13786 * @return string Actual Content-Type
13788 function get_type()
13790 if (isset($this->file->headers['content-type']))
13792 if (!isset($this->file->headers['content-encoding'])
13793 && ($this->file->headers['content-type'] === 'text/plain'
13794 || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
13795 || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'))
13797 return $this->text_or_binary();
13800 if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
13802 $official = substr($this->file->headers['content-type'], 0, $pos);
13804 else
13806 $official = $this->file->headers['content-type'];
13808 $official = strtolower($official);
13810 if ($official === 'unknown/unknown'
13811 || $official === 'application/unknown')
13813 return $this->unknown();
13815 elseif (substr($official, -4) === '+xml'
13816 || $official === 'text/xml'
13817 || $official === 'application/xml')
13819 return $official;
13821 elseif (substr($official, 0, 6) === 'image/')
13823 if ($return = $this->image())
13825 return $return;
13827 else
13829 return $official;
13832 elseif ($official === 'text/html')
13834 return $this->feed_or_html();
13836 else
13838 return $official;
13841 else
13843 return $this->unknown();
13848 * Sniff text or binary
13850 * @access private
13851 * @return string Actual Content-Type
13853 function text_or_binary()
13855 if (substr($this->file->body, 0, 2) === "\xFE\xFF"
13856 || substr($this->file->body, 0, 2) === "\xFF\xFE"
13857 || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
13858 || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
13860 return 'text/plain';
13862 elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
13864 return 'application/octect-stream';
13866 else
13868 return 'text/plain';
13873 * Sniff unknown
13875 * @access private
13876 * @return string Actual Content-Type
13878 function unknown()
13880 $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
13881 if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
13882 || strtolower(substr($this->file->body, $ws, 5)) === '<html'
13883 || strtolower(substr($this->file->body, $ws, 7)) === '<script')
13885 return 'text/html';
13887 elseif (substr($this->file->body, 0, 5) === '%PDF-')
13889 return 'application/pdf';
13891 elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
13893 return 'application/postscript';
13895 elseif (substr($this->file->body, 0, 6) === 'GIF87a'
13896 || substr($this->file->body, 0, 6) === 'GIF89a')
13898 return 'image/gif';
13900 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
13902 return 'image/png';
13904 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
13906 return 'image/jpeg';
13908 elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
13910 return 'image/bmp';
13912 else
13914 return $this->text_or_binary();
13919 * Sniff images
13921 * @access private
13922 * @return string Actual Content-Type
13924 function image()
13926 if (substr($this->file->body, 0, 6) === 'GIF87a'
13927 || substr($this->file->body, 0, 6) === 'GIF89a')
13929 return 'image/gif';
13931 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
13933 return 'image/png';
13935 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
13937 return 'image/jpeg';
13939 elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
13941 return 'image/bmp';
13943 else
13945 return false;
13950 * Sniff HTML
13952 * @access private
13953 * @return string Actual Content-Type
13955 function feed_or_html()
13957 $len = strlen($this->file->body);
13958 $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
13960 while ($pos < $len)
13962 switch ($this->file->body[$pos])
13964 case "\x09":
13965 case "\x0A":
13966 case "\x0D":
13967 case "\x20":
13968 $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
13969 continue 2;
13971 case '<':
13972 $pos++;
13973 break;
13975 default:
13976 return 'text/html';
13979 if (substr($this->file->body, $pos, 3) === '!--')
13981 $pos += 3;
13982 if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
13984 $pos += 3;
13986 else
13988 return 'text/html';
13991 elseif (substr($this->file->body, $pos, 1) === '!')
13993 if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
13995 $pos++;
13997 else
13999 return 'text/html';
14002 elseif (substr($this->file->body, $pos, 1) === '?')
14004 if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
14006 $pos += 2;
14008 else
14010 return 'text/html';
14013 elseif (substr($this->file->body, $pos, 3) === 'rss'
14014 || substr($this->file->body, $pos, 7) === 'rdf:RDF')
14016 return 'application/rss+xml';
14018 elseif (substr($this->file->body, $pos, 4) === 'feed')
14020 return 'application/atom+xml';
14022 else
14024 return 'text/html';
14028 return 'text/html';
14033 * Parses the XML Declaration
14035 * @package SimplePie
14037 class SimplePie_XML_Declaration_Parser
14040 * XML Version
14042 * @access public
14043 * @var string
14045 var $version = '1.0';
14048 * Encoding
14050 * @access public
14051 * @var string
14053 var $encoding = 'UTF-8';
14056 * Standalone
14058 * @access public
14059 * @var bool
14061 var $standalone = false;
14064 * Current state of the state machine
14066 * @access private
14067 * @var string
14069 var $state = 'before_version_name';
14072 * Input data
14074 * @access private
14075 * @var string
14077 var $data = '';
14080 * Input data length (to avoid calling strlen() everytime this is needed)
14082 * @access private
14083 * @var int
14085 var $data_length = 0;
14088 * Current position of the pointer
14090 * @var int
14091 * @access private
14093 var $position = 0;
14096 * Create an instance of the class with the input data
14098 * @access public
14099 * @param string $data Input data
14101 function SimplePie_XML_Declaration_Parser($data)
14103 $this->data = $data;
14104 $this->data_length = strlen($this->data);
14108 * Parse the input data
14110 * @access public
14111 * @return bool true on success, false on failure
14113 function parse()
14115 while ($this->state && $this->state !== 'emit' && $this->has_data())
14117 $state = $this->state;
14118 $this->$state();
14120 $this->data = '';
14121 if ($this->state === 'emit')
14123 return true;
14125 else
14127 $this->version = '';
14128 $this->encoding = '';
14129 $this->standalone = '';
14130 return false;
14135 * Check whether there is data beyond the pointer
14137 * @access private
14138 * @return bool true if there is further data, false if not
14140 function has_data()
14142 return (bool) ($this->position < $this->data_length);
14146 * Advance past any whitespace
14148 * @return int Number of whitespace characters passed
14150 function skip_whitespace()
14152 $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
14153 $this->position += $whitespace;
14154 return $whitespace;
14158 * Read value
14160 function get_value()
14162 $quote = substr($this->data, $this->position, 1);
14163 if ($quote === '"' || $quote === "'")
14165 $this->position++;
14166 $len = strcspn($this->data, $quote, $this->position);
14167 if ($this->has_data())
14169 $value = substr($this->data, $this->position, $len);
14170 $this->position += $len + 1;
14171 return $value;
14174 return false;
14177 function before_version_name()
14179 if ($this->skip_whitespace())
14181 $this->state = 'version_name';
14183 else
14185 $this->state = false;
14189 function version_name()
14191 if (substr($this->data, $this->position, 7) === 'version')
14193 $this->position += 7;
14194 $this->skip_whitespace();
14195 $this->state = 'version_equals';
14197 else
14199 $this->state = false;
14203 function version_equals()
14205 if (substr($this->data, $this->position, 1) === '=')
14207 $this->position++;
14208 $this->skip_whitespace();
14209 $this->state = 'version_value';
14211 else
14213 $this->state = false;
14217 function version_value()
14219 if ($this->version = $this->get_value())
14221 $this->skip_whitespace();
14222 if ($this->has_data())
14224 $this->state = 'encoding_name';
14226 else
14228 $this->state = 'emit';
14231 else
14233 $this->state = false;
14237 function encoding_name()
14239 if (substr($this->data, $this->position, 8) === 'encoding')
14241 $this->position += 8;
14242 $this->skip_whitespace();
14243 $this->state = 'encoding_equals';
14245 else
14247 $this->state = 'standalone_name';
14251 function encoding_equals()
14253 if (substr($this->data, $this->position, 1) === '=')
14255 $this->position++;
14256 $this->skip_whitespace();
14257 $this->state = 'encoding_value';
14259 else
14261 $this->state = false;
14265 function encoding_value()
14267 if ($this->encoding = $this->get_value())
14269 $this->skip_whitespace();
14270 if ($this->has_data())
14272 $this->state = 'standalone_name';
14274 else
14276 $this->state = 'emit';
14279 else
14281 $this->state = false;
14285 function standalone_name()
14287 if (substr($this->data, $this->position, 10) === 'standalone')
14289 $this->position += 10;
14290 $this->skip_whitespace();
14291 $this->state = 'standalone_equals';
14293 else
14295 $this->state = false;
14299 function standalone_equals()
14301 if (substr($this->data, $this->position, 1) === '=')
14303 $this->position++;
14304 $this->skip_whitespace();
14305 $this->state = 'standalone_value';
14307 else
14309 $this->state = false;
14313 function standalone_value()
14315 if ($standalone = $this->get_value())
14317 switch ($standalone)
14319 case 'yes':
14320 $this->standalone = true;
14321 break;
14323 case 'no':
14324 $this->standalone = false;
14325 break;
14327 default:
14328 $this->state = false;
14329 return;
14332 $this->skip_whitespace();
14333 if ($this->has_data())
14335 $this->state = false;
14337 else
14339 $this->state = 'emit';
14342 else
14344 $this->state = false;
14349 class SimplePie_Locator
14351 var $useragent;
14352 var $timeout;
14353 var $file;
14354 var $local = array();
14355 var $elsewhere = array();
14356 var $file_class = 'SimplePie_File';
14357 var $cached_entities = array();
14358 var $http_base;
14359 var $base;
14360 var $base_location = 0;
14361 var $checked_feeds = 0;
14362 var $max_checked_feeds = 10;
14363 var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer';
14365 function SimplePie_Locator(&$file, $timeout = 10, $useragent = null, $file_class = 'SimplePie_File', $max_checked_feeds = 10, $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer')
14367 $this->file =& $file;
14368 $this->file_class = $file_class;
14369 $this->useragent = $useragent;
14370 $this->timeout = $timeout;
14371 $this->max_checked_feeds = $max_checked_feeds;
14372 $this->content_type_sniffer_class = $content_type_sniffer_class;
14375 function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
14377 if ($this->is_feed($this->file))
14379 return $this->file;
14382 if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
14384 $sniffer = new $this->content_type_sniffer_class($this->file);
14385 if ($sniffer->get_type() !== 'text/html')
14387 return null;
14391 if ($type & ~SIMPLEPIE_LOCATOR_NONE)
14393 $this->get_base();
14396 if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
14398 return $working[0];
14401 if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
14403 if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
14405 return $working;
14408 if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
14410 return $working;
14413 if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
14415 return $working;
14418 if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
14420 return $working;
14423 return null;
14426 function is_feed(&$file)
14428 if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
14430 $sniffer = new $this->content_type_sniffer_class($file);
14431 $sniffed = $sniffer->get_type();
14432 if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
14434 return true;
14436 else
14438 return false;
14441 elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
14443 return true;
14445 else
14447 return false;
14451 function get_base()
14453 $this->http_base = $this->file->url;
14454 $this->base = $this->http_base;
14455 $elements = SimplePie_Misc::get_element('base', $this->file->body);
14456 foreach ($elements as $element)
14458 if ($element['attribs']['href']['data'] !== '')
14460 $this->base = SimplePie_Misc::absolutize_url(trim($element['attribs']['href']['data']), $this->http_base);
14461 $this->base_location = $element['offset'];
14462 break;
14467 function autodiscovery()
14469 $links = array_merge(SimplePie_Misc::get_element('link', $this->file->body), SimplePie_Misc::get_element('a', $this->file->body), SimplePie_Misc::get_element('area', $this->file->body));
14470 $done = array();
14471 $feeds = array();
14472 foreach ($links as $link)
14474 if ($this->checked_feeds === $this->max_checked_feeds)
14476 break;
14478 if (isset($link['attribs']['href']['data']) && isset($link['attribs']['rel']['data']))
14480 $rel = array_unique(SimplePie_Misc::space_seperated_tokens(strtolower($link['attribs']['rel']['data'])));
14482 if ($this->base_location < $link['offset'])
14484 $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base);
14486 else
14488 $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base);
14491 if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !empty($link['attribs']['type']['data']) && in_array(strtolower(SimplePie_Misc::parse_mime($link['attribs']['type']['data'])), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href]))
14493 $this->checked_feeds++;
14494 $feed = new $this->file_class($href, $this->timeout, 5, null, $this->useragent);
14495 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))
14497 $feeds[$href] = $feed;
14500 $done[] = $href;
14504 if (!empty($feeds))
14506 return array_values($feeds);
14508 else {
14509 return null;
14513 function get_links()
14515 $links = SimplePie_Misc::get_element('a', $this->file->body);
14516 foreach ($links as $link)
14518 if (isset($link['attribs']['href']['data']))
14520 $href = trim($link['attribs']['href']['data']);
14521 $parsed = SimplePie_Misc::parse_url($href);
14522 if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
14524 if ($this->base_location < $link['offset'])
14526 $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base);
14528 else
14530 $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base);
14533 $current = SimplePie_Misc::parse_url($this->file->url);
14535 if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
14537 $this->local[] = $href;
14539 else
14541 $this->elsewhere[] = $href;
14546 $this->local = array_unique($this->local);
14547 $this->elsewhere = array_unique($this->elsewhere);
14548 if (!empty($this->local) || !empty($this->elsewhere))
14550 return true;
14552 return null;
14555 function extension(&$array)
14557 foreach ($array as $key => $value)
14559 if ($this->checked_feeds === $this->max_checked_feeds)
14561 break;
14563 if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
14565 $this->checked_feeds++;
14566 $feed = new $this->file_class($value, $this->timeout, 5, null, $this->useragent);
14567 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))
14569 return $feed;
14571 else
14573 unset($array[$key]);
14577 return null;
14580 function body(&$array)
14582 foreach ($array as $key => $value)
14584 if ($this->checked_feeds === $this->max_checked_feeds)
14586 break;
14588 if (preg_match('/(rss|rdf|atom|xml)/i', $value))
14590 $this->checked_feeds++;
14591 $feed = new $this->file_class($value, $this->timeout, 5, null, $this->useragent);
14592 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))
14594 return $feed;
14596 else
14598 unset($array[$key]);
14602 return null;
14606 class SimplePie_Parser
14608 var $error_code;
14609 var $error_string;
14610 var $current_line;
14611 var $current_column;
14612 var $current_byte;
14613 var $separator = ' ';
14614 var $namespace = array('');
14615 var $element = array('');
14616 var $xml_base = array('');
14617 var $xml_base_explicit = array(false);
14618 var $xml_lang = array('');
14619 var $data = array();
14620 var $datas = array(array());
14621 var $current_xhtml_construct = -1;
14622 var $encoding;
14624 function parse(&$data, $encoding)
14626 // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
14627 if (strtoupper($encoding) === 'US-ASCII')
14629 $this->encoding = 'UTF-8';
14631 else
14633 $this->encoding = $encoding;
14636 // Strip BOM:
14637 // UTF-32 Big Endian BOM
14638 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
14640 $data = substr($data, 4);
14642 // UTF-32 Little Endian BOM
14643 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
14645 $data = substr($data, 4);
14647 // UTF-16 Big Endian BOM
14648 elseif (substr($data, 0, 2) === "\xFE\xFF")
14650 $data = substr($data, 2);
14652 // UTF-16 Little Endian BOM
14653 elseif (substr($data, 0, 2) === "\xFF\xFE")
14655 $data = substr($data, 2);
14657 // UTF-8 BOM
14658 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
14660 $data = substr($data, 3);
14663 if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
14665 $declaration = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
14666 if ($declaration->parse())
14668 $data = substr($data, $pos + 2);
14669 $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
14671 else
14673 $this->error_string = 'SimplePie bug! Please report this!';
14674 return false;
14678 $return = true;
14680 static $xml_is_sane = null;
14681 if ($xml_is_sane === null)
14683 $parser_check = xml_parser_create();
14684 xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
14685 xml_parser_free($parser_check);
14686 $xml_is_sane = isset($values[0]['value']);
14689 // Create the parser
14690 if ($xml_is_sane)
14692 $xml = xml_parser_create_ns($this->encoding, $this->separator);
14693 xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
14694 xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
14695 xml_set_object($xml, $this);
14696 xml_set_character_data_handler($xml, 'cdata');
14697 xml_set_element_handler($xml, 'tag_open', 'tag_close');
14699 // Parse!
14700 if (!xml_parse($xml, $data, true))
14702 $this->error_code = xml_get_error_code($xml);
14703 $this->error_string = xml_error_string($this->error_code);
14704 $return = false;
14706 $this->current_line = xml_get_current_line_number($xml);
14707 $this->current_column = xml_get_current_column_number($xml);
14708 $this->current_byte = xml_get_current_byte_index($xml);
14709 xml_parser_free($xml);
14710 return $return;
14712 else
14714 libxml_clear_errors();
14715 $xml = new XMLReader();
14716 $xml->xml($data);
14717 while (@$xml->read())
14719 switch ($xml->nodeType)
14722 case constant('XMLReader::END_ELEMENT'):
14723 if ($xml->namespaceURI !== '')
14725 $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
14727 else
14729 $tagName = $xml->localName;
14731 $this->tag_close(null, $tagName);
14732 break;
14733 case constant('XMLReader::ELEMENT'):
14734 $empty = $xml->isEmptyElement;
14735 if ($xml->namespaceURI !== '')
14737 $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
14739 else
14741 $tagName = $xml->localName;
14743 $attributes = array();
14744 while ($xml->moveToNextAttribute())
14746 if ($xml->namespaceURI !== '')
14748 $attrName = $xml->namespaceURI . $this->separator . $xml->localName;
14750 else
14752 $attrName = $xml->localName;
14754 $attributes[$attrName] = $xml->value;
14756 $this->tag_open(null, $tagName, $attributes);
14757 if ($empty)
14759 $this->tag_close(null, $tagName);
14761 break;
14762 case constant('XMLReader::TEXT'):
14764 case constant('XMLReader::CDATA'):
14765 $this->cdata(null, $xml->value);
14766 break;
14769 if ($error = libxml_get_last_error())
14771 $this->error_code = $error->code;
14772 $this->error_string = $error->message;
14773 $this->current_line = $error->line;
14774 $this->current_column = $error->column;
14775 return false;
14777 else
14779 return true;
14784 function get_error_code()
14786 return $this->error_code;
14789 function get_error_string()
14791 return $this->error_string;
14794 function get_current_line()
14796 return $this->current_line;
14799 function get_current_column()
14801 return $this->current_column;
14804 function get_current_byte()
14806 return $this->current_byte;
14809 function get_data()
14811 return $this->data;
14814 function tag_open($parser, $tag, $attributes)
14816 list($this->namespace[], $this->element[]) = $this->split_ns($tag);
14818 $attribs = array();
14819 foreach ($attributes as $name => $value)
14821 list($attrib_namespace, $attribute) = $this->split_ns($name);
14822 $attribs[$attrib_namespace][$attribute] = $value;
14825 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
14827 $this->xml_base[] = SimplePie_Misc::absolutize_url($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base));
14828 $this->xml_base_explicit[] = true;
14830 else
14832 $this->xml_base[] = end($this->xml_base);
14833 $this->xml_base_explicit[] = end($this->xml_base_explicit);
14836 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
14838 $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
14840 else
14842 $this->xml_lang[] = end($this->xml_lang);
14845 if ($this->current_xhtml_construct >= 0)
14847 $this->current_xhtml_construct++;
14848 if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML)
14850 $this->data['data'] .= '<' . end($this->element);
14851 if (isset($attribs['']))
14853 foreach ($attribs[''] as $name => $value)
14855 $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
14858 $this->data['data'] .= '>';
14861 else
14863 $this->datas[] =& $this->data;
14864 $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
14865 $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));
14866 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')
14867 || (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'))
14869 $this->current_xhtml_construct = 0;
14874 function cdata($parser, $cdata)
14876 if ($this->current_xhtml_construct >= 0)
14878 $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
14880 else
14882 $this->data['data'] .= $cdata;
14886 function tag_close($parser, $tag)
14888 if ($this->current_xhtml_construct >= 0)
14890 $this->current_xhtml_construct--;
14891 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')))
14893 $this->data['data'] .= '</' . end($this->element) . '>';
14896 if ($this->current_xhtml_construct === -1)
14898 $this->data =& $this->datas[count($this->datas) - 1];
14899 array_pop($this->datas);
14902 array_pop($this->element);
14903 array_pop($this->namespace);
14904 array_pop($this->xml_base);
14905 array_pop($this->xml_base_explicit);
14906 array_pop($this->xml_lang);
14909 function split_ns($string)
14911 static $cache = array();
14912 if (!isset($cache[$string]))
14914 if ($pos = strpos($string, $this->separator))
14916 static $separator_length;
14917 if (!$separator_length)
14919 $separator_length = strlen($this->separator);
14921 $namespace = substr($string, 0, $pos);
14922 $local_name = substr($string, $pos + $separator_length);
14923 if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
14925 $namespace = SIMPLEPIE_NAMESPACE_ITUNES;
14928 // Normalize the Media RSS namespaces
14929 if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG)
14931 $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
14933 $cache[$string] = array($namespace, $local_name);
14935 else
14937 $cache[$string] = array('', $string);
14940 return $cache[$string];
14945 * @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
14947 class SimplePie_Sanitize
14949 // Private vars
14950 var $base;
14952 // Options
14953 var $remove_div = true;
14954 var $image_handler = '';
14955 var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
14956 var $encode_instead_of_strip = false;
14957 var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
14958 var $strip_comments = false;
14959 var $output_encoding = 'UTF-8';
14960 var $enable_cache = true;
14961 var $cache_location = './cache';
14962 var $cache_name_function = 'md5';
14963 var $cache_class = 'SimplePie_Cache';
14964 var $file_class = 'SimplePie_File';
14965 var $timeout = 10;
14966 var $useragent = '';
14967 var $force_fsockopen = false;
14969 var $replace_url_attributes = array(
14970 'a' => 'href',
14971 'area' => 'href',
14972 'blockquote' => 'cite',
14973 'del' => 'cite',
14974 'form' => 'action',
14975 'img' => array('longdesc', 'src'),
14976 'input' => 'src',
14977 'ins' => 'cite',
14978 'q' => 'cite'
14981 function remove_div($enable = true)
14983 $this->remove_div = (bool) $enable;
14986 function set_image_handler($page = false)
14988 if ($page)
14990 $this->image_handler = (string) $page;
14992 else
14994 $this->image_handler = false;
14998 function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
15000 if (isset($enable_cache))
15002 $this->enable_cache = (bool) $enable_cache;
15005 if ($cache_location)
15007 $this->cache_location = (string) $cache_location;
15010 if ($cache_name_function)
15012 $this->cache_name_function = (string) $cache_name_function;
15015 if ($cache_class)
15017 $this->cache_class = (string) $cache_class;
15021 function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
15023 if ($file_class)
15025 $this->file_class = (string) $file_class;
15028 if ($timeout)
15030 $this->timeout = (string) $timeout;
15033 if ($useragent)
15035 $this->useragent = (string) $useragent;
15038 if ($force_fsockopen)
15040 $this->force_fsockopen = (string) $force_fsockopen;
15044 function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'))
15046 if ($tags)
15048 if (is_array($tags))
15050 $this->strip_htmltags = $tags;
15052 else
15054 $this->strip_htmltags = explode(',', $tags);
15057 else
15059 $this->strip_htmltags = false;
15063 function encode_instead_of_strip($encode = false)
15065 $this->encode_instead_of_strip = (bool) $encode;
15068 function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
15070 if ($attribs)
15072 if (is_array($attribs))
15074 $this->strip_attributes = $attribs;
15076 else
15078 $this->strip_attributes = explode(',', $attribs);
15081 else
15083 $this->strip_attributes = false;
15087 function strip_comments($strip = false)
15089 $this->strip_comments = (bool) $strip;
15092 function set_output_encoding($encoding = 'UTF-8')
15094 $this->output_encoding = (string) $encoding;
15098 * Set element/attribute key/value pairs of HTML attributes
15099 * containing URLs that need to be resolved relative to the feed
15101 * @access public
15102 * @since 1.0
15103 * @param array $element_attribute Element/attribute key/value pairs
15105 function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite'))
15107 $this->replace_url_attributes = (array) $element_attribute;
15110 function sanitize($data, $type, $base = '')
15112 $data = trim($data);
15113 if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
15115 if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
15117 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))
15119 $type |= SIMPLEPIE_CONSTRUCT_HTML;
15121 else
15123 $type |= SIMPLEPIE_CONSTRUCT_TEXT;
15127 if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
15129 $data = base64_decode($data);
15132 if ($type & SIMPLEPIE_CONSTRUCT_XHTML)
15134 if ($this->remove_div)
15136 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
15137 $data = preg_replace('/<\/div>$/', '', $data);
15139 else
15141 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
15145 if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
15147 // Strip comments
15148 if ($this->strip_comments)
15150 $data = SimplePie_Misc::strip_comments($data);
15153 // Strip out HTML tags and attributes that might cause various security problems.
15154 // Based on recommendations by Mark Pilgrim at:
15155 // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
15156 if ($this->strip_htmltags)
15158 foreach ($this->strip_htmltags as $tag)
15160 $pcre = "/<($tag)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$tag" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>|(\/)?>)/siU';
15161 while (preg_match($pcre, $data))
15163 $data = preg_replace_callback($pcre, array(&$this, 'do_strip_htmltags'), $data);
15168 if ($this->strip_attributes)
15170 foreach ($this->strip_attributes as $attrib)
15172 $data = preg_replace('/(<[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*)' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . trim($attrib) . '(?:\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>/', '\1\2\3>', $data);
15176 // Replace relative URLs
15177 $this->base = $base;
15178 foreach ($this->replace_url_attributes as $element => $attributes)
15180 $data = $this->replace_urls($data, $element, $attributes);
15183 // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
15184 if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
15186 $images = SimplePie_Misc::get_element('img', $data);
15187 foreach ($images as $img)
15189 if (isset($img['attribs']['src']['data']))
15191 $image_url = call_user_func($this->cache_name_function, $img['attribs']['src']['data']);
15192 $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $image_url, 'spi');
15194 if ($cache->load())
15196 $img['attribs']['src']['data'] = $this->image_handler . $image_url;
15197 $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data);
15199 else
15201 $file = new $this->file_class($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen);
15202 $headers = $file->headers;
15204 if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
15206 if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
15208 $img['attribs']['src']['data'] = $this->image_handler . $image_url;
15209 $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data);
15211 else
15213 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);
15221 // Having (possibly) taken stuff out, there may now be whitespace at the beginning/end of the data
15222 $data = trim($data);
15225 if ($type & SIMPLEPIE_CONSTRUCT_IRI)
15227 $data = SimplePie_Misc::absolutize_url($data, $base);
15230 if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
15232 $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
15235 if ($this->output_encoding !== 'UTF-8')
15237 $data = SimplePie_Misc::change_encoding($data, 'UTF-8', $this->output_encoding);
15240 return $data;
15243 function replace_urls($data, $tag, $attributes)
15245 if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
15247 $elements = SimplePie_Misc::get_element($tag, $data);
15248 foreach ($elements as $element)
15250 if (is_array($attributes))
15252 foreach ($attributes as $attribute)
15254 if (isset($element['attribs'][$attribute]['data']))
15256 $element['attribs'][$attribute]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attribute]['data'], $this->base);
15257 $new_element = SimplePie_Misc::element_implode($element);
15258 $data = str_replace($element['full'], $new_element, $data);
15259 $element['full'] = $new_element;
15263 elseif (isset($element['attribs'][$attributes]['data']))
15265 $element['attribs'][$attributes]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attributes]['data'], $this->base);
15266 $data = str_replace($element['full'], SimplePie_Misc::element_implode($element), $data);
15270 return $data;
15273 function do_strip_htmltags($match)
15275 if ($this->encode_instead_of_strip)
15277 if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
15279 $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
15280 $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
15281 return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
15283 else
15285 return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
15288 elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
15290 return $match[4];
15292 else
15294 return '';