From 91d55b797acf64322fa396dbfea34a78ea6b970f Mon Sep 17 00:00:00 2001 From: Guillaume Turri Date: Sun, 21 Nov 2010 12:16:21 +0100 Subject: First step to upgrade to SimplePie 1.2 --- inc/FeedParser.php | 1 + inc/SimplePie.php | 13380 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 8778 insertions(+), 4603 deletions(-) (limited to 'inc') diff --git a/inc/FeedParser.php b/inc/FeedParser.php index 9d00e7abf..b98350da7 100644 --- a/inc/FeedParser.php +++ b/inc/FeedParser.php @@ -49,6 +49,7 @@ class FeedParser_File extends SimplePie_File { */ function FeedParser_File($url, $timeout=10, $redirects=5, $headers=null, $useragent=null, $force_fsockopen=false) { + parent::__construct(); $this->http = new DokuHTTPClient(); $this->success = $this->http->sendRequest($url); diff --git a/inc/SimplePie.php b/inc/SimplePie.php index 99c9f3226..1bbc2c0ec 100644 --- a/inc/SimplePie.php +++ b/inc/SimplePie.php @@ -5,7 +5,7 @@ * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * - * Copyright (c) 2004-2007, Ryan Parman and Geoffrey Sneddon + * Copyright (c) 2004-2009, Ryan Parman and Geoffrey Sneddon * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -33,8 +33,8 @@ * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie - * @version "Razzleberry" - * @copyright 2004-2007 Ryan Parman, Geoffrey Sneddon + * @version 1.2.1-dev + * @copyright 2004-2009 Ryan Parman, Geoffrey Sneddon * @author Ryan Parman * @author Geoffrey Sneddon * @link http://simplepie.org/ SimplePie @@ -51,18 +51,18 @@ define('SIMPLEPIE_NAME', 'SimplePie'); /** * SimplePie Version */ -define('SIMPLEPIE_VERSION', '1.0.1'); +define('SIMPLEPIE_VERSION', '1.2.1-dev'); /** * SimplePie Build * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::parse_date() only every load of simplepie.inc) */ -define('SIMPLEPIE_BUILD', 20070719221955); +define('SIMPLEPIE_BUILD', gmdate('YmdHis', SimplePie_Misc::parse_date(substr('$Date$', 7, 25)) ? SimplePie_Misc::parse_date(substr('$Date$', 7, 25)) : filemtime(__FILE__))); /** * SimplePie Website URL */ -define('SIMPLEPIE_URL', 'http://simplepie.org/'); +define('SIMPLEPIE_URL', 'http://simplepie.org'); /** * SimplePie Useragent @@ -242,10 +242,25 @@ define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32); */ define('SIMPLEPIE_CONSTRUCT_ALL', 63); +/** + * Don't change case + */ +define('SIMPLEPIE_SAME_CASE', 1); + +/** + * Change to lowercase + */ +define('SIMPLEPIE_LOWERCASE', 2); + +/** + * Change to uppercase + */ +define('SIMPLEPIE_UPPERCASE', 4); + /** * PCRE for HTML attributes */ -define('SIMPLEPIE_PCRE_HTML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)(?:\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[a-z0-9\-._:]*)))?)*)\s*'); +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]*'); /** * PCRE for XML attributes @@ -287,6 +302,12 @@ define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/'); */ define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/'); +/** + * RSS 2.0 Namespace + * (Stupid, I know, but I'm certain it will confuse people less with support.) + */ +define('SIMPLEPIE_NAMESPACE_RSS_20', ''); + /** * DC 1.0 Namespace */ @@ -312,6 +333,11 @@ define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss'); */ define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/'); +/** + * Wrong Media RSS Namespace + */ +define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss'); + /** * iTunes RSS Namespace */ @@ -332,15 +358,40 @@ define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignment */ define('SIMPLEPIE_PHP5', version_compare(PHP_VERSION, '5.0.0', '>=')); +/** + * No file source + */ +define('SIMPLEPIE_FILE_SOURCE_NONE', 0); + +/** + * Remote file source + */ +define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1); + +/** + * Local file source + */ +define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2); + +/** + * fsockopen() file source + */ +define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4); + +/** + * cURL file source + */ +define('SIMPLEPIE_FILE_SOURCE_CURL', 8); + +/** + * file_get_contents() file source + */ +define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16); + /** * SimplePie * * @package SimplePie - * @version "Razzleberry" - * @copyright 2004-2007 Ryan Parman, Geoffrey Sneddon - * @author Ryan Parman - * @author Geoffrey Sneddon - * @todo Option for type of fetching (cache, not modified header, fetch, etc.) */ class SimplePie { @@ -406,6 +457,14 @@ class SimplePie */ var $force_fsockopen = false; + /** + * @var bool Force the given data/URL to be treated as a feed no matter what + * it appears like + * @see SimplePie::force_feed() + * @access private + */ + var $force_feed = false; + /** * @var bool Enable/Disable XML dump * @see SimplePie::enable_xml_dump() @@ -561,6 +620,20 @@ class SimplePie */ var $restriction_class = 'SimplePie_Restriction'; + /** + * @var string Class used for content-type sniffing + * @see SimplePie::set_content_type_sniffer_class() + * @access private + */ + var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer'; + + /** + * @var string Class used for item sources. + * @see SimplePie::set_source_class() + * @access private + */ + var $source_class = 'SimplePie_Source'; + /** * @var mixed Set javascript query string parameter (false, or * anything type-cast to false, disables this feature) @@ -576,6 +649,13 @@ class SimplePie */ var $max_checked_feeds = 10; + /** + * @var array All the feeds found during the autodiscovery process + * @see SimplePie::get_all_discovered_feeds() + * @access private + */ + var $all_discovered_feeds = array(); + /** * @var string Web-accessible path to the handler_favicon.php file. * @see SimplePie::set_favicon_handler() @@ -610,6 +690,13 @@ class SimplePie */ var $config_settings = null; + /** + * @var integer Stores the number of items to return per-feed with multifeeds. + * @see SimplePie::set_item_limit() + * @access private + */ + var $item_limit = 0; + /** * @var array Stores the default attributes to be stripped by strip_attributes(). * @see SimplePie::strip_attributes() @@ -677,6 +764,45 @@ class SimplePie return md5(serialize($this->data)); } + /** + * Remove items that link back to this before destroying this object + */ + function __destruct() + { + if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode')) + { + if (!empty($this->data['items'])) + { + foreach ($this->data['items'] as $item) + { + $item->__destruct(); + } + unset($item, $this->data['items']); + } + if (!empty($this->data['ordered_items'])) + { + foreach ($this->data['ordered_items'] as $item) + { + $item->__destruct(); + } + unset($item, $this->data['ordered_items']); + } + } + } + + /** + * Force the given data/URL to be treated as a feed no matter what it + * appears like + * + * @access public + * @since 1.1 + * @param bool $enable Force the given data/URL to be treated as a feed + */ + function force_feed($enable = false) + { + $this->force_feed = (bool) $enable; + } + /** * This is the URL of the feed you want to parse. * @@ -718,7 +844,7 @@ class SimplePie */ function set_file(&$file) { - if (SimplePie_Misc::is_a($file, 'SimplePie_File')) + if (is_a($file, 'SimplePie_File')) { $this->feed_url = $file->url; $this->file =& $file; @@ -741,7 +867,7 @@ class SimplePie */ function set_raw_data($data) { - $this->raw_data = trim($data); + $this->raw_data = $data; } /** @@ -1156,6 +1282,44 @@ class SimplePie return false; } + /** + * Allows you to change which class SimplePie uses for content-type sniffing. + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Content_Type_Sniffer')) + { + $this->content_type_sniffer_class = $class; + return true; + } + return false; + } + + /** + * Allows you to change which class SimplePie uses item sources. + * Useful when you are overloading or extending SimplePie's default classes. + * + * @access public + * @param string $class Name of custom class. + * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation + * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation + */ + function set_source_class($class = 'SimplePie_Source') + { + if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Source')) + { + $this->source_class = $class; + return true; + } + return false; + } + /** * Allows you to override the default user agent string. * @@ -1294,7 +1458,7 @@ class SimplePie */ function set_favicon_handler($page = false, $qs = 'i') { - if ($page != false) + if ($page !== false) { $this->favicon_handler = $page . '?' . $qs . '='; } @@ -1313,7 +1477,7 @@ class SimplePie */ function set_image_handler($page = false, $qs = 'i') { - if ($page != false) + if ($page !== false) { $this->sanitize->set_image_handler($page . '?' . $qs . '='); } @@ -1323,47 +1487,44 @@ class SimplePie } } + /** + * Set the limit for items returned per-feed with multifeeds. + * + * @access public + * @param integer $limit The maximum number of items to return. + */ + function set_item_limit($limit = 0) + { + $this->item_limit = (int) $limit; + } + function init() { - if ((function_exists('version_compare') && version_compare(PHP_VERSION, '4.1.0', '<')) || !extension_loaded('xml') || !extension_loaded('pcre')) + // Check absolute bare minimum requirements. + if ((function_exists('version_compare') && version_compare(PHP_VERSION, '4.3.0', '<')) || !extension_loaded('xml') || !extension_loaded('pcre')) { return false; } - if (isset($_GET[$this->javascript])) + // 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. + elseif (!extension_loaded('xmlreader')) { - if (function_exists('ob_gzhandler')) + static $xml_is_sane = null; + if ($xml_is_sane === null) { - ob_start('ob_gzhandler'); + $parser_check = xml_parser_create(); + xml_parse_into_struct($parser_check, '&', $values); + xml_parser_free($parser_check); + $xml_is_sane = isset($values[0]['value']); } - header('Content-type: text/javascript; charset: UTF-8'); - header('Cache-Control: must-revalidate'); - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days - ?> -function embed_odeo(link) { - document.writeln(''); -} - -function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) { - if (placeholder != '') { - document.writeln(''); - } - else { - document.writeln(''); - } -} - -function embed_flash(bgcolor, width, height, link, loop, type) { - document.writeln(''); -} - -function embed_flv(width, height, link, placeholder, loop, player) { - document.writeln(''); -} + if (!$xml_is_sane) + { + return false; + } + } -function embed_wmedia(width, height, link) { - document.writeln(''); -} - javascript])) + { + SimplePie_Misc::output_javascript(); exit; } @@ -1383,7 +1544,7 @@ function embed_wmedia(width, height, link) { // Decide whether to enable caching if ($this->cache && $parsed_feed_url['scheme'] !== '') { - $cache = new $this->cache_class($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'); + $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'); } // If it's enabled and we don't want an XML dump, use the cache if ($cache && !$this->xml_dump) @@ -1393,13 +1554,13 @@ function embed_wmedia(width, height, link) { if (!empty($this->data)) { // If the cache is for an outdated build of SimplePie - if (!isset($this->data['build']) || $this->data['build'] != SIMPLEPIE_BUILD) + if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD) { $cache->unlink(); $this->data = array(); } // If we've hit a collision just rerun it with caching disabled - elseif (isset($this->data['url']) && $this->data['url'] != $this->feed_url) + elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url) { $cache = false; $this->data = array(); @@ -1411,7 +1572,7 @@ function embed_wmedia(width, height, link) { if ($cache->mtime() + $this->autodiscovery_cache_duration > time()) { // Do not need to do feed autodiscovery yet. - if ($this->data['feed_url'] == $this->data['url']) + if ($this->data['feed_url'] === $this->data['url']) { $cache->unlink(); $this->data = array(); @@ -1436,12 +1597,12 @@ function embed_wmedia(width, height, link) { } if (isset($this->data['headers']['etag'])) { - $headers['if-none-match'] = $this->data['headers']['etag']; + $headers['if-none-match'] = '"' . $this->data['headers']['etag'] . '"'; } $file = new $this->file_class($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen); if ($file->success) { - if ($file->status_code == 304) + if ($file->status_code === 304) { $cache->touch(); return true; @@ -1473,7 +1634,7 @@ function embed_wmedia(width, height, link) { // 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. if (!isset($file)) { - if (SimplePie_Misc::is_a($this->file, 'SimplePie_File') && $this->file->url == $this->feed_url) + if (is_a($this->file, 'SimplePie_File') && $this->file->url === $this->feed_url) { $file =& $this->file; } @@ -1483,7 +1644,7 @@ function embed_wmedia(width, height, link) { } } // If the file connection has an error, set SimplePie::error to that and quit - if (!$file->success) + if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300))) { $this->error = $file->error; if (!empty($this->data)) @@ -1496,148 +1657,150 @@ function embed_wmedia(width, height, link) { } } - // Check if the supplied URL is a feed, if it isn't, look for it. - $locate = new $this->locator_class($file, $this->timeout, $this->useragent, $this->file_class, $this->max_checked_feeds); - if (!$locate->is_feed($file)) + if (!$this->force_feed) { - // We need to unset this so that if SimplePie::set_file() has been called that object is untouched - unset($file); - if ($file = $locate->find($this->autodiscovery)) + // Check if the supplied URL is a feed, if it isn't, look for it. + $locate = new $this->locator_class($file, $this->timeout, $this->useragent, $this->file_class, $this->max_checked_feeds, $this->content_type_sniffer_class); + if (!$locate->is_feed($file)) { - if ($cache) + // We need to unset this so that if SimplePie::set_file() has been called that object is untouched + unset($file); + if ($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)) { - if (!$cache->save(array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD))) + if ($cache) { - trigger_error("$cache->name is not writeable", E_USER_WARNING); + $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD); + if (!$cache->save($this)) + { + 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); + } + $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'); } - $cache = new $this->cache_class($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'); + $this->feed_url = $file->url; + } + else + { + $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."; + SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__); + return false; } - $this->feed_url = $file->url; - } - else - { - $this->error = "A feed could not be found at $this->feed_url"; - SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__); - return false; } + $locate = null; } - $locate = null; $headers = $file->headers; - $data = trim($file->body); - unset($file); + $data = $file->body; + $sniffer = new $this->content_type_sniffer_class($file); + $sniffed = $sniffer->get_type(); } else { $data = $this->raw_data; } + // Set up array of possible encodings + $encodings = array(); + // First check to see if input has been overridden. if ($this->input_encoding !== false) { - $encoding = $this->input_encoding; - } - // Second try HTTP headers - elseif (isset($headers['content-type']) && preg_match('/;[\x09\x20]*charset=([^;]*)/i', $headers['content-type'], $charset)) - { - $encoding = $charset[1]; - } - // Then prolog, if at the very start of the document - elseif (preg_match("/^<\?xml[\x20\x9\xD\xA]+version([\x20\x9\xD\xA]+)?=([\x20\x9\xD\xA]+)?(\"1.0\"|'1.0'|\"1.1\"|'1.1')[\x20\x9\xD\xA]+encoding([\x20\x9\xD\xA]+)?=([\x20\x9\xD\xA]+)?(\"[A-Za-z][A-Za-z0-9._\-]*\"|'[A-Za-z][A-Za-z0-9._\-]*')([\x20\x9\xD\xA]+standalone([\x20\x9\xD\xA]+)?=([\x20\x9\xD\xA]+)?(\"(yes|no)\"|'(yes|no)'))?([\x20\x9\xD\xA]+)?\?>/", $data, $prolog)) - { - $encoding = substr($prolog[6], 1, -1); - } - // UTF-32 Big Endian BOM - elseif (strpos($data, "\x0\x0\xFE\xFF") === 0) - { - $encoding = 'UTF-32be'; - } - // UTF-32 Little Endian BOM - elseif (strpos($data, "\xFF\xFE\x0\x0") === 0) - { - $encoding = 'UTF-32'; - } - // UTF-16 Big Endian BOM - elseif (strpos($data, "\xFE\xFF") === 0) - { - $encoding = 'UTF-16be'; - } - // UTF-16 Little Endian BOM - elseif (strpos($data, "\xFF\xFE") === 0) - { - $encoding = 'UTF-16le'; - } - // UTF-8 BOM - elseif (strpos($data, "\xEF\xBB\xBF") === 0) - { - $encoding = 'UTF-8'; - } - // Fallback to the default (US-ASCII for text/xml, ISO-8859-1 for text/* MIME types, UTF-8 otherwise) - elseif (isset($headers['content-type']) && strtolower(SimplePie_Misc::parse_mime($headers['content-type'])) == 'text/xml') - { - $encoding = 'US-ASCII'; - } - elseif (isset($headers['content-type']) && SimplePie_Misc::stripos(SimplePie_Misc::parse_mime($headers['content-type']), 'text/') === 0) - { - $encoding = 'ISO-8859-1'; - } - else - { - $encoding = 'UTF-8'; + $encodings[] = $this->input_encoding; } - // Change the encoding to UTF-8 (as we always use UTF-8 internally) - if ($encoding != 'UTF-8') + $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity'); + $text_types = array('text/xml', 'text/xml-external-parsed-entity'); + + // RFC 3023 (only applies to sniffed content) + if (isset($sniffed)) { - $data = SimplePie_Misc::change_encoding($data, $encoding, 'UTF-8'); + if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml') + { + if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset)) + { + $encodings[] = strtoupper($charset[1]); + } + $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data)); + $encodings[] = 'UTF-8'; + } + elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml') + { + if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset)) + { + $encodings[] = $charset[1]; + } + $encodings[] = 'US-ASCII'; + } + // Text MIME-type default + elseif (substr($sniffed, 0, 5) === 'text/') + { + $encodings[] = 'US-ASCII'; + } } - // Strip illegal characters - $data = SimplePie_Misc::utf8_bad_replace($data); + // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1 + $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data)); + $encodings[] = 'UTF-8'; + $encodings[] = 'ISO-8859-1'; + + // There's no point in trying an encoding twice + $encodings = array_unique($encodings); - $parser = new $this->parser_class(); - $parser->pre_process($data, 'UTF-8'); - // If we want the XML, just output that and quit + // If we want the XML, just output that with the most likely encoding and quit if ($this->xml_dump) { - header('Content-type: text/xml; charset=UTF-8'); + header('Content-type: text/xml; charset=' . $encodings[0]); echo $data; exit; } - // If it's parsed fine - elseif ($parser->parse($data)) + + // Loop through each possible encoding, till we return something, or run out of possibilities + foreach ($encodings as $encoding) { - unset($data); - $this->data = $parser->get_data(); - if (isset($this->data['child'])) + // Change the encoding to UTF-8 (as we always use UTF-8 internally) + if ($utf8_data = SimplePie_Misc::change_encoding($data, $encoding, 'UTF-8')) { - if (isset($headers)) - { - $this->data['headers'] = $headers; - } - $this->data['build'] = SIMPLEPIE_BUILD; + // Create new parser + $parser = new $this->parser_class(); - // Cache the file if caching is enabled - if ($cache && !$cache->save($this->data)) + // If it's parsed fine + if ($parser->parse($utf8_data, 'UTF-8')) { - trigger_error("$cache->name is not writeable", E_USER_WARNING); + $this->data = $parser->get_data(); + if ($this->get_type() & ~SIMPLEPIE_TYPE_NONE) + { + if (isset($headers)) + { + $this->data['headers'] = $headers; + } + $this->data['build'] = SIMPLEPIE_BUILD; + + // Cache the file if caching is enabled + if ($cache && !$cache->save($this)) + { + 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); + } + return true; + } + else + { + $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed."; + SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__); + return false; + } } - return true; - } - else - { - $this->error = "A feed could not be found at $this->feed_url"; - SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__); - return false; } } - // If we have an error, just set SimplePie::error to it and quit + if (isset($parser)) + { + // We have an error, just set SimplePie_Misc::error to it and quit + $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()); + } else { - $this->error = sprintf('XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column()); - SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__); - return false; + $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.'; } + SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__); + return false; } elseif (!empty($this->multifeed_url)) { @@ -1730,18 +1893,18 @@ function embed_wmedia(width, height, link) { $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090; } } - elseif (isset($this->data['child']['']['rss'])) + elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'])) { $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL; - if (isset($this->data['child']['']['rss'][0]['attribs']['']['version'])) + if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version'])) { - switch (trim($this->data['child']['']['rss'][0]['attribs']['']['version'])) + switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version'])) { case '0.91': $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091; - if (isset($this->data['child']['']['rss'][0]['child']['']['skiphours']['hour'][0]['data'])) + if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data'])) { - switch (trim($this->data['child']['']['rss'][0]['child']['']['skiphours']['hour'][0]['data'])) + switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data'])) { case '0': $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE; @@ -1783,6 +1946,7 @@ function embed_wmedia(width, height, link) { /** * Returns the URL for the favicon of the feed's website. * + * @todo Cache atom:icon * @access public * @since 1.0 */ @@ -1798,26 +1962,36 @@ function embed_wmedia(width, height, link) { if ($this->cache && $this->favicon_handler) { - $cache = new $this->cache_class($this->cache_location, call_user_func($this->cache_name_function, $favicon), 'spi'); + $favicon_filename = call_user_func($this->cache_name_function, $favicon); + $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $favicon_filename, 'spi'); if ($cache->load()) { - return $this->sanitize($this->favicon_handler . rawurlencode($favicon), SIMPLEPIE_CONSTRUCT_IRI); + return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI); } else { $file = new $this->file_class($favicon, $this->timeout / 10, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen); - if ($file->success && ($file->status_code == 200 || ($file->status_code > 206 && $file->status_code < 300)) && strlen($file->body) > 0) + 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) { - if ($cache->save(array('headers' => $file->headers, 'body' => $file->body))) + $sniffer = new $this->content_type_sniffer_class($file); + if (substr($sniffer->get_type(), 0, 6) === 'image/') { - return $this->sanitize($this->favicon_handler . rawurlencode($favicon), SIMPLEPIE_CONSTRUCT_IRI); + if ($cache->save(array('headers' => $file->headers, 'body' => $file->body))) + { + return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI); + } + else + { + 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); + return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI); + } } + // not an image else { - trigger_error("$cache->name is not writeable", E_USER_WARNING); - return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI); + return false; } } } @@ -1863,7 +2037,7 @@ function embed_wmedia(width, height, link) { { if ($this->feed_url !== null) { - return 'outlook' . $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI); + return $this->sanitize('outlook' . SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI); } else { @@ -1908,12 +2082,12 @@ function embed_wmedia(width, height, link) { { if ($this->subscribe_url()) { - $return = $this->sanitize($feed_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->subscribe_url()); + $return = $feed_url . rawurlencode($this->feed_url); if ($site_url !== null && $this->get_link() !== null) { - $return .= $this->sanitize($site_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_link()); + $return .= $site_url . rawurlencode($this->get_link()); } - return $return; + return $this->sanitize($return, SIMPLEPIE_CONSTRUCT_IRI); } else { @@ -1928,7 +2102,7 @@ function embed_wmedia(width, height, link) { function subscribe_bloglines() { - return urldecode($this->subscribe_service('http://www.bloglines.com/sub/')); + return $this->subscribe_service('http://www.bloglines.com/sub/'); } function subscribe_eskobo() @@ -2022,9 +2196,9 @@ function embed_wmedia(width, height, link) { } if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION) { - if (isset($this->data['child']['']['rss'][0]['child'][$namespace][$tag])) + if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag])) { - return $this->data['child']['']['rss'][0]['child'][$namespace][$tag]; + return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]; } } return null; @@ -2062,7 +2236,7 @@ function embed_wmedia(width, height, link) { } if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION) { - if ($channel = $this->get_feed_tags('', 'channel')) + if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel')) { if (isset($channel[0]['child'][$namespace][$tag])) { @@ -2098,7 +2272,7 @@ function embed_wmedia(width, height, link) { } if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION) { - if ($image = $this->get_channel_tags('', 'image')) + if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image')) { if (isset($image[0]['child'][$namespace][$tag])) { @@ -2119,10 +2293,6 @@ function embed_wmedia(width, height, link) { { return $this->get_link(); } - elseif (isset($this->data['headers']['content-location'])) - { - return SimplePie_Misc::absolutize_url($this->data['headers']['content-location'], $this->subscribe_url()); - } else { return $this->subscribe_url(); @@ -2152,7 +2322,7 @@ function embed_wmedia(width, height, link) { { return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - elseif ($return = $this->get_channel_tags('', 'title')) + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title')) { return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } @@ -2170,12 +2340,12 @@ function embed_wmedia(width, height, link) { } } - function get_link($key = 0, $rel = 'alternate') + function get_category($key = 0) { - $links = $this->get_links($rel); - if (isset($links[$key])) + $categories = $this->get_categories(); + if (isset($categories[$key])) { - return $links[$key]; + return $categories[$key]; } else { @@ -2183,33 +2353,257 @@ function embed_wmedia(width, height, link) { } } - /** - * Added for parity between the parent-level and the item/entry-level. - */ - function get_permalink() + function get_categories() { - return $this->get_link(0); - } + $categories = array(); - function get_links($rel = 'alternate') - { - if (!isset($this->data['links'])) + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category) { - $this->data['links'] = array(); - if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link')) + $term = null; + $scheme = null; + $label = null; + if (isset($category['attribs']['']['term'])) { - foreach ($links as $link) - { - if (isset($link['attribs']['']['href'])) - { - $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; - $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); - } - } + $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT); } - if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link')) + if (isset($category['attribs']['']['scheme'])) { - foreach ($links as $link) + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] = new $this->category_class($term, $scheme, $label); + } + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category) + { + // This is really the label, but keep this as the term also for BC. + // Label will also work on retrieving because that falls back to term. + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + if (isset($category['attribs']['']['domain'])) + { + $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = null; + } + $categories[] = new $this->category_class($term, $scheme, null); + } + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category) + { + $categories[] = new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category) + { + $categories[] = new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + + if (!empty($categories)) + { + return SimplePie_Misc::array_unique($categories); + } + else + { + return null; + } + } + + function get_author($key = 0) + { + $authors = $this->get_authors(); + if (isset($authors[$key])) + { + return $authors[$key]; + } + else + { + return null; + } + } + + function get_authors() + { + $authors = array(); + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author) + { + $name = null; + $uri = null; + $email = null; + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) + { + $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) + { + $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])); + } + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $authors[] = new $this->author_class($name, $uri, $email); + } + } + if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author')) + { + $name = null; + $url = null; + $email = null; + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) + { + $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) + { + $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])); + } + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $authors[] = new $this->author_class($name, $url, $email); + } + } + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author) + { + $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author) + { + $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author) + { + $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + + if (!empty($authors)) + { + return SimplePie_Misc::array_unique($authors); + } + else + { + return null; + } + } + + function get_contributor($key = 0) + { + $contributors = $this->get_contributors(); + if (isset($contributors[$key])) + { + return $contributors[$key]; + } + else + { + return null; + } + } + + function get_contributors() + { + $contributors = array(); + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor) + { + $name = null; + $uri = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) + { + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) + { + $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])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $contributors[] = new $this->author_class($name, $uri, $email); + } + } + foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor) + { + $name = null; + $url = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) + { + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) + { + $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])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $contributors[] = new $this->author_class($name, $url, $email); + } + } + + if (!empty($contributors)) + { + return SimplePie_Misc::array_unique($contributors); + } + else + { + return null; + } + } + + function get_link($key = 0, $rel = 'alternate') + { + $links = $this->get_links($rel); + if (isset($links[$key])) + { + return $links[$key]; + } + else + { + return null; + } + } + + /** + * Added for parity between the parent-level and the item/entry-level. + */ + function get_permalink() + { + return $this->get_link(0); + } + + function get_links($rel = 'alternate') + { + if (!isset($this->data['links'])) + { + $this->data['links'] = array(); + if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link')) + { + foreach ($links as $link) + { + if (isset($link['attribs']['']['href'])) + { + $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; + $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + } + } + } + if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link')) + { + foreach ($links as $link) { if (isset($link['attribs']['']['href'])) { @@ -2227,7 +2621,7 @@ function embed_wmedia(width, height, link) { { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); } - if ($links = $this->get_channel_tags('', 'link')) + if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link')) { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); } @@ -2247,7 +2641,7 @@ function embed_wmedia(width, height, link) { $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key]; } } - elseif (substr($key, 0, 41) == SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY) + elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY) { $this->data['links'][substr($key, 41)] =& $this->data['links'][$key]; } @@ -2265,6 +2659,11 @@ function embed_wmedia(width, height, link) { } } + function get_all_discovered_feeds() + { + return $this->all_discovered_feeds; + } + function get_description() { if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle')) @@ -2283,9 +2682,9 @@ function embed_wmedia(width, height, link) { { return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - elseif ($return = $this->get_channel_tags('', 'description')) + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description')) { - return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description')) { @@ -2315,7 +2714,11 @@ function embed_wmedia(width, height, link) { { return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); } - elseif ($return = $this->get_channel_tags('', 'copyright')) + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright')) { return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } @@ -2335,7 +2738,7 @@ function embed_wmedia(width, height, link) { function get_language() { - if ($return = $this->get_channel_tags('', 'language')) + if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language')) { return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } @@ -2371,11 +2774,12 @@ function embed_wmedia(width, height, link) { function get_latitude() { + if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat')) { return (float) $return[0]['data']; } - elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match)) + 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)) { return (float) $match[1]; } @@ -2395,7 +2799,7 @@ function embed_wmedia(width, height, link) { { return (float) $return[0]['data']; } - elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match)) + 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)) { return (float) $match[2]; } @@ -2415,7 +2819,7 @@ function embed_wmedia(width, height, link) { { return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - elseif ($return = $this->get_image_tags('', 'title')) + elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title')) { return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } @@ -2455,7 +2859,7 @@ function embed_wmedia(width, height, link) { { return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); } - elseif ($return = $this->get_image_tags('', 'url')) + elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url')) { return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); } @@ -2475,7 +2879,7 @@ function embed_wmedia(width, height, link) { { return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); } - elseif ($return = $this->get_image_tags('', 'link')) + elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link')) { return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); } @@ -2487,11 +2891,11 @@ function embed_wmedia(width, height, link) { function get_image_width() { - if ($return = $this->get_image_tags('', 'width')) + if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width')) { return round($return[0]['data']); } - elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags('', 'url')) + elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url')) { return 88.0; } @@ -2503,11 +2907,11 @@ function embed_wmedia(width, height, link) { function get_image_height() { - if ($return = $this->get_image_tags('', 'height')) + if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height')) { return round($return[0]['data']); } - elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags('', 'url')) + elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url')) { return 31.0; } @@ -2519,8 +2923,9 @@ function embed_wmedia(width, height, link) { function get_item_quantity($max = 0) { + $max = (int) $max; $qty = count($this->get_items()); - if ($max == 0) + if ($max === 0) { return $qty; } @@ -2545,50 +2950,54 @@ function embed_wmedia(width, height, link) { function get_items($start = 0, $end = 0) { - if (!empty($this->multifeed_objects)) - { - return SimplePie::merge_items($this->multifeed_objects, $start, $end); - } - elseif (!isset($this->data['items'])) + if (!isset($this->data['items'])) { - if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry')) + if (!empty($this->multifeed_objects)) { - $keys = array_keys($items); - foreach ($keys as $key) - { - $this->data['items'][] = new $this->item_class($this, $items[$key]); - } + $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit); } - if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry')) + else { - $keys = array_keys($items); - foreach ($keys as $key) + $this->data['items'] = array(); + if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry')) { - $this->data['items'][] = new $this->item_class($this, $items[$key]); + $keys = array_keys($items); + foreach ($keys as $key) + { + $this->data['items'][] = new $this->item_class($this, $items[$key]); + } } - } - if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item')) - { - $keys = array_keys($items); - foreach ($keys as $key) + if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry')) { - $this->data['items'][] = new $this->item_class($this, $items[$key]); + $keys = array_keys($items); + foreach ($keys as $key) + { + $this->data['items'][] = new $this->item_class($this, $items[$key]); + } } - } - if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item')) - { - $keys = array_keys($items); - foreach ($keys as $key) + if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item')) { - $this->data['items'][] = new $this->item_class($this, $items[$key]); + $keys = array_keys($items); + foreach ($keys as $key) + { + $this->data['items'][] = new $this->item_class($this, $items[$key]); + } } - } - if ($items = $this->get_channel_tags('', 'item')) - { - $keys = array_keys($items); - foreach ($keys as $key) + if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item')) + { + $keys = array_keys($items); + foreach ($keys as $key) + { + $this->data['items'][] = new $this->item_class($this, $items[$key]); + } + } + if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item')) { - $this->data['items'][] = new $this->item_class($this, $items[$key]); + $keys = array_keys($items); + foreach ($keys as $key) + { + $this->data['items'][] = new $this->item_class($this, $items[$key]); + } } } } @@ -2596,7 +3005,7 @@ function embed_wmedia(width, height, link) { if (!empty($this->data['items'])) { // If we want to order it by date, check if all items have a date, and then sort it - if ($this->order_by_date) + if ($this->order_by_date && empty($this->multifeed_objects)) { if (!isset($this->data['ordered_items'])) { @@ -2624,7 +3033,7 @@ function embed_wmedia(width, height, link) { } // Slice the data as desired - if ($end == 0) + if ($end === 0) { return array_slice($items, $start); } @@ -2639,21 +3048,27 @@ function embed_wmedia(width, height, link) { } } + /** + * @static + */ function sort_items($a, $b) { return $a->get_date('U') <= $b->get_date('U'); } - function merge_items($urls, $start = 0, $end = 0) + /** + * @static + */ + function merge_items($urls, $start = 0, $end = 0, $limit = 0) { if (is_array($urls) && sizeof($urls) > 0) { $items = array(); foreach ($urls as $arg) { - if (SimplePie_Misc::is_a($arg, 'SimplePie')) + if (is_a($arg, 'SimplePie')) { - $items = array_merge($items, $arg->get_items()); + $items = array_merge($items, $arg->get_items(0, $limit)); } else { @@ -2676,7 +3091,7 @@ function embed_wmedia(width, height, link) { usort($items, array('SimplePie', 'sort_items')); } - if ($end == 0) + if ($end === 0) { return array_slice($items, $start); } @@ -2709,6 +3124,17 @@ class SimplePie_Item return md5(serialize($this->data)); } + /** + * Remove items that link back to this before destroying this object + */ + function __destruct() + { + if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode')) + { + unset($this->feed); + } + } + function get_item_tags($namespace, $tag) { if (isset($this->data['child'][$namespace][$tag])) @@ -2738,78 +3164,85 @@ class SimplePie_Item function get_id($hash = false) { - if ($hash) + if (!$hash) { - return $this->__toString(); + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (($return = $this->get_permalink()) !== null) + { + return $return; + } + elseif (($return = $this->get_title()) !== null) + { + return $return; + } } - elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id')) + if ($this->get_permalink() !== null || $this->get_title() !== null) { - return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + return md5($this->get_permalink() . $this->get_title()); } - elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id')) + else { - return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + return md5(serialize($this->data)); } - elseif ($return = $this->get_item_tags('', 'guid')) + } + + function get_title() + { + if (!isset($this->data['title'])) { - return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); - } - elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier')) - { - return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); - } - elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier')) - { - return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); - } - elseif (($return = $this->get_permalink()) !== null) - { - return $return; - } - elseif (($return = $this->get_title()) !== null) - { - return $return; - } - else - { - return $this->__toString(); - } - } - - function get_title() - { - if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title')) - { - return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); - } - elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title')) - { - return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); - } - elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title')) - { - return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); - } - elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title')) - { - return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); - } - elseif ($return = $this->get_item_tags('', 'title')) - { - return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); - } - elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title')) - { - return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); - } - elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title')) - { - return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); - } - else - { - return null; + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title')) + { + $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $this->data['title'] = null; + } } + return $this->data['title']; } function get_description($description_only = false) @@ -2826,7 +3259,7 @@ class SimplePie_Item { return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - elseif ($return = $this->get_item_tags('', 'description')) + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description')) { return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); } @@ -2916,9 +3349,20 @@ class SimplePie_Item } $categories[] = new $this->feed->category_class($term, $scheme, $label); } - foreach ((array) $this->get_item_tags('', 'category') as $category) + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category) { - $categories[] = new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + // This is really the label, but keep this as the term also for BC. + // Label will also work on retrieving because that falls back to term. + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + if (isset($category['attribs']['']['domain'])) + { + $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = null; + } + $categories[] = new $this->feed->category_class($term, $scheme, null); } foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category) { @@ -2952,9 +3396,77 @@ class SimplePie_Item } } - /** - * @todo Atom inheritance (item author, source author, feed author) - */ + function get_contributor($key = 0) + { + $contributors = $this->get_contributors(); + if (isset($contributors[$key])) + { + return $contributors[$key]; + } + else + { + return null; + } + } + + function get_contributors() + { + $contributors = array(); + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor) + { + $name = null; + $uri = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) + { + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) + { + $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])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $contributors[] = new $this->feed->author_class($name, $uri, $email); + } + } + foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor) + { + $name = null; + $url = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) + { + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) + { + $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])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $contributors[] = new $this->feed->author_class($name, $url, $email); + } + } + + if (!empty($contributors)) + { + return SimplePie_Misc::array_unique($contributors); + } + else + { + return null; + } + } + function get_authors() { $authors = array(); @@ -2991,18 +3503,18 @@ class SimplePie_Item } if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) { - $uri = $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])); + $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])); } if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) { $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - if ($name !== null || $email !== null || $uri !== null) + if ($name !== null || $email !== null || $url !== null) { $authors[] = new $this->feed->author_class($name, $url, $email); } } - if ($author = $this->get_item_tags('', 'author')) + if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author')) { $authors[] = new $this->feed->author_class(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); } @@ -3023,6 +3535,34 @@ class SimplePie_Item { return SimplePie_Misc::array_unique($authors); } + elseif (($source = $this->get_source()) && ($authors = $source->get_authors())) + { + return $authors; + } + elseif ($authors = $this->feed->get_authors()) + { + return $authors; + } + else + { + return null; + } + } + + function get_copyright() + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights')) + { + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } else { return null; @@ -3053,7 +3593,7 @@ class SimplePie_Item { $this->data['date']['raw'] = $return[0]['data']; } - elseif ($return = $this->get_item_tags('', 'pubDate')) + elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate')) { $this->data['date']['raw'] = $return[0]['data']; } @@ -3068,7 +3608,8 @@ class SimplePie_Item if (!empty($this->data['date']['raw'])) { - $this->data['date']['parsed'] = SimplePie_Misc::parse_date($this->data['date']['raw']); + $parser = SimplePie_Parse_Date::get(); + $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']); } else { @@ -3173,13 +3714,13 @@ class SimplePie_Item { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); } - if ($links = $this->get_item_tags('', 'link')) + if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link')) { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); } - if ($links = $this->get_item_tags('', 'guid')) + if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid')) { - if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) == 'true') + if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true') { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); } @@ -3200,7 +3741,7 @@ class SimplePie_Item $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key]; } } - elseif (substr($key, 0, 41) == SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY) + elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY) { $this->data['links'][substr($key, 41)] =& $this->data['links'][$key]; } @@ -3241,7 +3782,6 @@ class SimplePie_Item * 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. * * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4). - * @todo Add support for itunes: tags. These should be relatively simple compared to media:. * @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). */ function get_enclosures() @@ -3767,7 +4307,7 @@ class SimplePie_Item $restriction_relationship = 'allow'; $restriction_type = null; $restriction_value = 'itunes'; - if (isset($restriction['data']) && strtolower($restriction['data']) == 'yes') + if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes') { $restriction_relationship = 'deny'; } @@ -3803,7 +4343,7 @@ class SimplePie_Item $restriction_relationship = 'allow'; $restriction_type = null; $restriction_value = 'itunes'; - if (isset($restriction['data']) && strtolower($restriction['data']) == 'yes') + if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes') { $restriction_relationship = 'deny'; } @@ -3856,624 +4396,657 @@ class SimplePie_Item // Clear the memory unset($parent); + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; + + // Elements + $captions = null; + $categories = null; + $copyrights = null; + $credits = null; + $description = null; + $hashes = null; + $keywords = null; + $player = null; + $ratings = null; + $restrictions = null; + $thumbnails = null; + $title = null; + // If we have media:group tags, loop through them. foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group) { - // If we have media:content tags, loop through them. - foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content) + if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'])) { - if (isset($content['attribs']['']['url'])) + // If we have media:content tags, loop through them. + foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content) { - // Attributes - $bitrate = null; - $channels = null; - $duration = null; - $expression = null; - $framerate = null; - $height = null; - $javascript = null; - $lang = null; - $length = null; - $medium = null; - $samplingrate = null; - $type = null; - $url = null; - $width = null; - - // Elements - $captions = null; - $categories = null; - $copyrights = null; - $credits = null; - $description = null; - $hashes = null; - $keywords = null; - $player = null; - $ratings = null; - $restrictions = null; - $thumbnails = null; - $title = null; - - // Start checking the attributes of media:content - if (isset($content['attribs']['']['bitrate'])) - { - $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($content['attribs']['']['channels'])) - { - $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($content['attribs']['']['duration'])) - { - $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT); - } - else - { - $duration = $duration_parent; - } - if (isset($content['attribs']['']['expression'])) - { - $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($content['attribs']['']['framerate'])) - { - $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($content['attribs']['']['height'])) - { - $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($content['attribs']['']['lang'])) - { - $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($content['attribs']['']['fileSize'])) - { - $length = ceil($content['attribs']['']['fileSize']); - } - if (isset($content['attribs']['']['medium'])) - { - $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($content['attribs']['']['samplingrate'])) - { - $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($content['attribs']['']['type'])) - { - $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($content['attribs']['']['width'])) + if (isset($content['attribs']['']['url'])) { - $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT); - } - $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + // Attributes + $bitrate = null; + $channels = null; + $duration = null; + $expression = null; + $framerate = null; + $height = null; + $javascript = null; + $lang = null; + $length = null; + $medium = null; + $samplingrate = null; + $type = null; + $url = null; + $width = null; + + // Elements + $captions = null; + $categories = null; + $copyrights = null; + $credits = null; + $description = null; + $hashes = null; + $keywords = null; + $player = null; + $ratings = null; + $restrictions = null; + $thumbnails = null; + $title = null; + + // Start checking the attributes of media:content + if (isset($content['attribs']['']['bitrate'])) + { + $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['channels'])) + { + $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['duration'])) + { + $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $duration = $duration_parent; + } + if (isset($content['attribs']['']['expression'])) + { + $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['framerate'])) + { + $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['height'])) + { + $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['lang'])) + { + $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['fileSize'])) + { + $length = ceil($content['attribs']['']['fileSize']); + } + if (isset($content['attribs']['']['medium'])) + { + $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['samplingrate'])) + { + $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['type'])) + { + $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($content['attribs']['']['width'])) + { + $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); - // Checking the other optional media: elements. Priority: media:content, media:group, item, channel + // Checking the other optional media: elements. Priority: media:content, media:group, item, channel - // CAPTIONS - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'])) - { - foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption) + // CAPTIONS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'])) { - $caption_type = null; - $caption_lang = null; - $caption_startTime = null; - $caption_endTime = null; - $caption_text = null; - if (isset($caption['attribs']['']['type'])) - { - $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($caption['attribs']['']['lang'])) + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption) { - $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + $caption_type = null; + $caption_lang = null; + $caption_startTime = null; + $caption_endTime = null; + $caption_text = null; + if (isset($caption['attribs']['']['type'])) + { + $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['lang'])) + { + $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['start'])) + { + $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['end'])) + { + $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['data'])) + { + $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $captions[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text); } - if (isset($caption['attribs']['']['start'])) + if (is_array($captions)) { - $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); + $captions = array_values(SimplePie_Misc::array_unique($captions)); } - if (isset($caption['attribs']['']['end'])) + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption) { - $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + $caption_type = null; + $caption_lang = null; + $caption_startTime = null; + $caption_endTime = null; + $caption_text = null; + if (isset($caption['attribs']['']['type'])) + { + $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['lang'])) + { + $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['start'])) + { + $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['attribs']['']['end'])) + { + $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($caption['data'])) + { + $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $captions[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text); } - if (isset($caption['data'])) + if (is_array($captions)) { - $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + $captions = array_values(SimplePie_Misc::array_unique($captions)); } - $captions[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text); } - if (is_array($captions)) + else { - $captions = array_values(SimplePie_Misc::array_unique($captions)); + $captions = $captions_parent; } - } - elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'])) - { - foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption) + + // CATEGORIES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'])) { - $caption_type = null; - $caption_lang = null; - $caption_startTime = null; - $caption_endTime = null; - $caption_text = null; - if (isset($caption['attribs']['']['type'])) - { - $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($caption['attribs']['']['lang'])) - { - $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($caption['attribs']['']['start'])) - { - $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($caption['attribs']['']['end'])) + foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category) { - $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); + $term = null; + $scheme = null; + $label = null; + if (isset($category['data'])) + { + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = 'http://search.yahoo.com/mrss/category_schema'; + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] = new $this->feed->category_class($term, $scheme, $label); } - if (isset($caption['data'])) + } + if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'])) + { + foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category) { - $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); + $term = null; + $scheme = null; + $label = null; + if (isset($category['data'])) + { + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = 'http://search.yahoo.com/mrss/category_schema'; + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] = new $this->feed->category_class($term, $scheme, $label); } - $captions[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text); } - if (is_array($captions)) + if (is_array($categories) && is_array($categories_parent)) { - $captions = array_values(SimplePie_Misc::array_unique($captions)); + $categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent))); + } + elseif (is_array($categories)) + { + $categories = array_values(SimplePie_Misc::array_unique($categories)); + } + elseif (is_array($categories_parent)) + { + $categories = array_values(SimplePie_Misc::array_unique($categories_parent)); } - } - else - { - $captions = $captions_parent; - } - // CATEGORIES - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'])) - { - foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category) + // COPYRIGHTS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'])) { - $term = null; - $scheme = null; - $label = null; - if (isset($category['data'])) + $copyright_url = null; + $copyright_label = null; + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) { - $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); } - if (isset($category['attribs']['']['scheme'])) + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'])) { - $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - else + $copyrights = new $this->feed->copyright_class($copyright_url, $copyright_label); + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'])) + { + $copyright_url = null; + $copyright_label = null; + if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) { - $scheme = 'http://search.yahoo.com/mrss/category_schema'; + $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); } - if (isset($category['attribs']['']['label'])) + if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'])) { - $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - $categories[] = new $this->feed->category_class($term, $scheme, $label); + $copyrights = new $this->feed->copyright_class($copyright_url, $copyright_label); } - } - if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'])) - { - foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category) + else { - $term = null; - $scheme = null; - $label = null; - if (isset($category['data'])) + $copyrights = $copyrights_parent; + } + + // CREDITS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit) { - $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + $credit_role = null; + $credit_scheme = null; + $credit_name = null; + if (isset($credit['attribs']['']['role'])) + { + $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($credit['attribs']['']['scheme'])) + { + $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $credit_scheme = 'urn:ebu'; + } + if (isset($credit['data'])) + { + $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $credits[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name); } - if (isset($category['attribs']['']['scheme'])) + if (is_array($credits)) { - $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + $credits = array_values(SimplePie_Misc::array_unique($credits)); } - else + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit) { - $scheme = 'http://search.yahoo.com/mrss/category_schema'; + $credit_role = null; + $credit_scheme = null; + $credit_name = null; + if (isset($credit['attribs']['']['role'])) + { + $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($credit['attribs']['']['scheme'])) + { + $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $credit_scheme = 'urn:ebu'; + } + if (isset($credit['data'])) + { + $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $credits[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name); } - if (isset($category['attribs']['']['label'])) + if (is_array($credits)) { - $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + $credits = array_values(SimplePie_Misc::array_unique($credits)); } - $categories[] = new $this->feed->category_class($term, $scheme, $label); } - } - if (is_array($categories) && is_array($categories_parent)) - { - $categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent))); - } - elseif (is_array($categories)) - { - $categories = array_values(SimplePie_Misc::array_unique($categories)); - } - elseif (is_array($categories_parent)) - { - $categories = array_values(SimplePie_Misc::array_unique($categories_parent)); - } - - // COPYRIGHTS - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'])) - { - $copyright_url = null; - $copyright_label = null; - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) + else { - $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); + $credits = $credits_parent; } - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'])) + + // DESCRIPTION + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'])) { - $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - $copyrights = new $this->feed->copyright_class($copyright_url, $copyright_label); - } - elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'])) - { - $copyright_url = null; - $copyright_label = null; - if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'])) { - $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); + $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'])) + else { - $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + $description = $description_parent; } - $copyrights = new $this->feed->copyright_class($copyright_url, $copyright_label); - } - else - { - $copyrights = $copyrights_parent; - } - // CREDITS - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'])) - { - foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit) + // HASHES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'])) { - $credit_role = null; - $credit_scheme = null; - $credit_name = null; - if (isset($credit['attribs']['']['role'])) + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash) { - $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); + $value = null; + $algo = null; + if (isset($hash['data'])) + { + $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($hash['attribs']['']['algo'])) + { + $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $algo = 'md5'; + } + $hashes[] = $algo.':'.$value; } - if (isset($credit['attribs']['']['scheme'])) + if (is_array($hashes)) { - $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + $hashes = array_values(SimplePie_Misc::array_unique($hashes)); } - else + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'])) + { + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash) { - $credit_scheme = 'urn:ebu'; + $value = null; + $algo = null; + if (isset($hash['data'])) + { + $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($hash['attribs']['']['algo'])) + { + $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $algo = 'md5'; + } + $hashes[] = $algo.':'.$value; } - if (isset($credit['data'])) + if (is_array($hashes)) { - $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); + $hashes = array_values(SimplePie_Misc::array_unique($hashes)); } - $credits[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name); } - if (is_array($credits)) + else { - $credits = array_values(SimplePie_Misc::array_unique($credits)); + $hashes = $hashes_parent; } - } - elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'])) - { - foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit) + + // KEYWORDS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'])) { - $credit_role = null; - $credit_scheme = null; - $credit_name = null; - if (isset($credit['attribs']['']['role'])) + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'])) { - $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); + $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords[] = trim($word); + } + unset($temp); } - if (isset($credit['attribs']['']['scheme'])) + if (is_array($keywords)) { - $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + $keywords = array_values(SimplePie_Misc::array_unique($keywords)); } - else + } + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'])) + { + if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'])) { - $credit_scheme = 'urn:ebu'; + $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); + foreach ($temp as $word) + { + $keywords[] = trim($word); + } + unset($temp); } - if (isset($credit['data'])) + if (is_array($keywords)) { - $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); + $keywords = array_values(SimplePie_Misc::array_unique($keywords)); } - $credits[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name); } - if (is_array($credits)) + else { - $credits = array_values(SimplePie_Misc::array_unique($credits)); + $keywords = $keywords_parent; } - } - else - { - $credits = $credits_parent; - } - - // DESCRIPTION - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'])) - { - $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); - } - elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'])) - { - $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); - } - else - { - $description = $description_parent; - } - // HASHES - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'])) - { - foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash) + // PLAYER + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) { - $value = null; - $algo = null; - if (isset($hash['data'])) - { - $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($hash['attribs']['']['algo'])) - { - $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); - } - else - { - $algo = 'md5'; - } - $hashes[] = $algo.':'.$value; + $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); } - if (is_array($hashes)) + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) { - $hashes = array_values(SimplePie_Misc::array_unique($hashes)); + $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); } - } - elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'])) - { - foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash) + else { - $value = null; - $algo = null; - if (isset($hash['data'])) - { - $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($hash['attribs']['']['algo'])) + $player = $player_parent; + } + + // RATINGS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'])) + { + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating) { - $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); + $rating_scheme = null; + $rating_value = null; + if (isset($rating['attribs']['']['scheme'])) + { + $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $rating_scheme = 'urn:simple'; + } + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings[] = new $this->feed->rating_class($rating_scheme, $rating_value); } - else + if (is_array($ratings)) { - $algo = 'md5'; + $ratings = array_values(SimplePie_Misc::array_unique($ratings)); } - $hashes[] = $algo.':'.$value; - } - if (is_array($hashes)) - { - $hashes = array_values(SimplePie_Misc::array_unique($hashes)); } - } - else - { - $hashes = $hashes_parent; - } - - // KEYWORDS - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'])) - { - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'])) + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'])) { - $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); - foreach ($temp as $word) + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating) { - $keywords[] = trim($word); + $rating_scheme = null; + $rating_value = null; + if (isset($rating['attribs']['']['scheme'])) + { + $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $rating_scheme = 'urn:simple'; + } + if (isset($rating['data'])) + { + $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $ratings[] = new $this->feed->rating_class($rating_scheme, $rating_value); } - unset($temp); - } - if (is_array($keywords)) - { - $keywords = array_values(SimplePie_Misc::array_unique($keywords)); - } - } - elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'])) - { - if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'])) - { - $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); - foreach ($temp as $word) + if (is_array($ratings)) { - $keywords[] = trim($word); + $ratings = array_values(SimplePie_Misc::array_unique($ratings)); } - unset($temp); } - if (is_array($keywords)) + else { - $keywords = array_values(SimplePie_Misc::array_unique($keywords)); + $ratings = $ratings_parent; } - } - else - { - $keywords = $keywords_parent; - } - - // PLAYER - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) - { - $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); - } - elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) - { - $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); - } - else - { - $player = $player_parent; - } - // RATINGS - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'])) - { - foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating) + // RESTRICTIONS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'])) { - $rating_scheme = null; - $rating_value = null; - if (isset($rating['attribs']['']['scheme'])) - { - $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); - } - else + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction) { - $rating_scheme = 'urn:simple'; + $restriction_relationship = null; + $restriction_type = null; + $restriction_value = null; + if (isset($restriction['attribs']['']['relationship'])) + { + $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['attribs']['']['type'])) + { + $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['data'])) + { + $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $restrictions[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value); } - if (isset($rating['data'])) + if (is_array($restrictions)) { - $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + $restrictions = array_values(SimplePie_Misc::array_unique($restrictions)); } - $ratings[] = new $this->feed->rating_class($rating_scheme, $rating_value); - } - if (is_array($ratings)) - { - $ratings = array_values(SimplePie_Misc::array_unique($ratings)); } - } - elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'])) - { - foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating) + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'])) { - $rating_scheme = null; - $rating_value = null; - if (isset($rating['attribs']['']['scheme'])) - { - $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); - } - else + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction) { - $rating_scheme = 'urn:simple'; + $restriction_relationship = null; + $restriction_type = null; + $restriction_value = null; + if (isset($restriction['attribs']['']['relationship'])) + { + $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['attribs']['']['type'])) + { + $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($restriction['data'])) + { + $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $restrictions[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value); } - if (isset($rating['data'])) + if (is_array($restrictions)) { - $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); + $restrictions = array_values(SimplePie_Misc::array_unique($restrictions)); } - $ratings[] = new $this->feed->rating_class($rating_scheme, $rating_value); } - if (is_array($ratings)) + else { - $ratings = array_values(SimplePie_Misc::array_unique($ratings)); + $restrictions = $restrictions_parent; } - } - else - { - $ratings = $ratings_parent; - } - // RESTRICTIONS - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'])) - { - foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction) + // THUMBNAILS + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'])) { - $restriction_relationship = null; - $restriction_type = null; - $restriction_value = null; - if (isset($restriction['attribs']['']['relationship'])) + foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) { - $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($restriction['attribs']['']['type'])) - { - $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); } - if (isset($restriction['data'])) + if (is_array($thumbnails)) { - $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails)); } - $restrictions[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value); } - if (is_array($restrictions)) - { - $restrictions = array_values(SimplePie_Misc::array_unique($restrictions)); - } - } - elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'])) - { - foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction) + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'])) { - $restriction_relationship = null; - $restriction_type = null; - $restriction_value = null; - if (isset($restriction['attribs']['']['relationship'])) - { - $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); - } - if (isset($restriction['attribs']['']['type'])) + foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) { - $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); + $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); } - if (isset($restriction['data'])) + if (is_array($thumbnails)) { - $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); + $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails)); } - $restrictions[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value); } - if (is_array($restrictions)) + else { - $restrictions = array_values(SimplePie_Misc::array_unique($restrictions)); + $thumbnails = $thumbnails_parent; } - } - else - { - $restrictions = $restrictions_parent; - } - // THUMBNAILS - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'])) - { - foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) - { - $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); - } - if (is_array($thumbnails)) + // TITLES + if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'])) { - $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails)); + $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - } - elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'])) - { - foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) + elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'])) { - $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); + $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - if (is_array($thumbnails)) + else { - $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails)); + $title = $title_parent; } - } - else - { - $thumbnails = $thumbnails_parent; - } - // TITLES - if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'])) - { - $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); - } - elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'])) - { - $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); - } - else - { - $title = $title_parent; + $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); } - - $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); } } } @@ -4884,7 +5457,7 @@ class SimplePie_Item foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link) { - if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] == 'enclosure') + if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure') { // Attributes $bitrate = null; @@ -4919,7 +5492,7 @@ class SimplePie_Item foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link) { - if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] == 'enclosure') + if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure') { // Attributes $bitrate = null; @@ -4952,7 +5525,7 @@ class SimplePie_Item } } - if ($enclosure = $this->get_item_tags('', 'enclosure')) + if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure')) { if (isset($enclosure[0]['attribs']['']['url'])) { @@ -4986,6 +5559,13 @@ class SimplePie_Item $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); } } + + 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)) + { + // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor + $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); + } + $this->data['enclosures'] = array_values(SimplePie_Misc::array_unique($this->data['enclosures'])); } if (!empty($this->data['enclosures'])) @@ -5004,7 +5584,7 @@ class SimplePie_Item { return (float) $return[0]['data']; } - elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match)) + 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)) { return (float) $match[1]; } @@ -5024,7 +5604,7 @@ class SimplePie_Item { return (float) $return[0]['data']; } - elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match)) + 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)) { return (float) $match[2]; } @@ -5034,6 +5614,18 @@ class SimplePie_Item } } + function get_source() + { + if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source')) + { + return new $this->feed->source_class($this, $return[0]); + } + else + { + return null; + } + } + /** * Creates the add_to_* methods' return data * @@ -5043,16 +5635,20 @@ class SimplePie_Item * (and suffix to the item permalink) * @return mixed URL if feed exists, false otherwise */ - function add_to_service($item_url, $title_url = null) + function add_to_service($item_url, $title_url = null, $summary_url = null) { if ($this->get_permalink() !== null) { - $return = $this->sanitize($item_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_permalink()); + $return = $item_url . rawurlencode($this->get_permalink()); if ($title_url !== null && $this->get_title() !== null) { - $return .= $this->sanitize($title_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_title()); + $return .= $title_url . rawurlencode($this->get_title()); } - return $return; + if ($summary_url !== null && $this->get_description() !== null) + { + $return .= $summary_url . rawurlencode($this->get_description()); + } + return $this->sanitize($return, SIMPLEPIE_CONSTRUCT_IRI); } else { @@ -5072,12 +5668,12 @@ class SimplePie_Item function add_to_delicious() { - return $this->add_to_service('http://del.icio.us/post/?v=3&url=', '&title='); + return $this->add_to_service('http://del.icio.us/post/?v=4&url=', '&title='); } function add_to_digg() { - return $this->add_to_service('http://digg.com/submit?phase=2&URL='); + return $this->add_to_service('http://digg.com/submit?url=', '&title=', '&bodytext='); } function add_to_furl() @@ -5131,224 +5727,78 @@ class SimplePie_Item } } -class SimplePie_Author +class SimplePie_Source { - var $name; - var $link; - var $email; + var $item; + var $data = array(); - // Constructor, used to input the data - function SimplePie_Author($name = null, $link = null, $email = null) + function SimplePie_Source($item, $data) { - $this->name = $name; - $this->link = $link; - $this->email = $email; + $this->item = $item; + $this->data = $data; } function __toString() { - // There is no $this->data here - return md5(serialize($this)); - } - - function get_name() - { - if ($this->name !== null) - { - return $this->name; - } - else - { - return null; - } - } - - function get_link() - { - if ($this->link !== null) - { - return $this->link; - } - else - { - return null; - } + return md5(serialize($this->data)); } - function get_email() + function get_source_tags($namespace, $tag) { - if ($this->email !== null) + if (isset($this->data['child'][$namespace][$tag])) { - return $this->email; + return $this->data['child'][$namespace][$tag]; } else { return null; } } -} - -class SimplePie_Category -{ - var $term; - var $scheme; - var $label; - - // Constructor, used to input the data - function SimplePie_Category($term = null, $scheme = null, $label = null) - { - $this->term = $term; - $this->scheme = $scheme; - $this->label = $label; - } - function __toString() + function get_base($element = array()) { - // There is no $this->data here - return md5(serialize($this)); + return $this->item->get_base($element); } - function get_term() + function sanitize($data, $type, $base = '') { - if ($this->term !== null) - { - return $this->term; - } - else - { - return null; - } + return $this->item->sanitize($data, $type, $base); } - function get_scheme() + function get_item() { - if ($this->scheme !== null) - { - return $this->scheme; - } - else - { - return null; - } + return $this->item; } - function get_label() + function get_title() { - if ($this->label !== null) - { - return $this->label; - } - else + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title')) { - return $this->get_term(); + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); } - } -} - -class SimplePie_Enclosure -{ - var $bitrate; - var $captions; - var $categories; - var $channels; - var $copyright; - var $credits; - var $description; - var $duration; - var $expression; - var $framerate; - var $handler; - var $hashes; - var $height; - var $javascript; - var $keywords; - var $lang; - var $length; - var $link; - var $medium; - var $player; - var $ratings; - var $restrictions; - var $samplingrate; - var $thumbnails; - var $title; - var $type; - var $width; - - // Constructor, used to input the data - 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) - { - $this->bitrate = $bitrate; - $this->captions = $captions; - $this->categories = $categories; - $this->channels = $channels; - $this->copyright = $copyright; - $this->credits = $credits; - $this->description = $description; - $this->duration = $duration; - $this->expression = $expression; - $this->framerate = $framerate; - $this->hashes = $hashes; - $this->height = $height; - $this->javascript = $javascript; - $this->keywords = $keywords; - $this->lang = $lang; - $this->length = $length; - $this->link = $link; - $this->medium = $medium; - $this->player = $player; - $this->ratings = $ratings; - $this->restrictions = $restrictions; - $this->samplingrate = $samplingrate; - $this->thumbnails = $thumbnails; - $this->title = $title; - $this->type = $type; - $this->width = $width; - if (class_exists('idna_convert')) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title')) { - $idn = new idna_convert; - $parsed = SimplePie_Misc::parse_url($link); - $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']); + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); } - $this->handler = $this->get_handler(); // Needs to load last - } - - function __toString() - { - // There is no $this->data here - return md5(serialize($this)); - } - - function get_bitrate() - { - if ($this->bitrate !== null) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title')) { - return $this->bitrate; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - else + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title')) { - return null; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - } - - function get_caption($key = 0) - { - $captions = $this->get_captions(); - if (isset($captions[$key])) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title')) { - return $captions[$key]; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - else + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title')) { - return null; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - } - - function get_captions() - { - if ($this->captions !== null) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title')) { - return $this->captions; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } else { @@ -5371,46 +5821,54 @@ class SimplePie_Enclosure function get_categories() { - if ($this->categories !== null) - { - return $this->categories; - } - else - { - return null; - } - } + $categories = array(); - function get_channels() - { - if ($this->channels !== null) + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category) { - return $this->channels; + $term = null; + $scheme = null; + $label = null; + if (isset($category['attribs']['']['term'])) + { + $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['scheme'])) + { + $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($category['attribs']['']['label'])) + { + $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); + } + $categories[] = new $this->item->feed->category_class($term, $scheme, $label); } - else + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category) { - return null; + // This is really the label, but keep this as the term also for BC. + // Label will also work on retrieving because that falls back to term. + $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); + if (isset($category['attribs']['']['domain'])) + { + $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT); + } + else + { + $scheme = null; + } + $categories[] = new $this->item->feed->category_class($term, $scheme, null); } - } - - function get_copyright() - { - if ($this->copyright !== null) + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category) { - return $this->copyright; + $categories[] = new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); } - else + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category) { - return null; + $categories[] = new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); } - } - function get_credit($key = 0) - { - $credits = $this->get_credits(); - if (isset($credits[$key])) + if (!empty($categories)) { - return $credits[$key]; + return SimplePie_Misc::array_unique($categories); } else { @@ -5418,11 +5876,12 @@ class SimplePie_Enclosure } } - function get_credits() + function get_author($key = 0) { - if ($this->credits !== null) + $authors = $this->get_authors(); + if (isset($authors[$key])) { - return $this->credits; + return $authors[$key]; } else { @@ -5430,68 +5889,140 @@ class SimplePie_Enclosure } } - function get_description() + function get_authors() { - if ($this->description !== null) - { - return $this->description; - } - else + $authors = array(); + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author) { - return null; + $name = null; + $uri = null; + $email = null; + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) + { + $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) + { + $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])); + } + if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $authors[] = new $this->item->feed->author_class($name, $uri, $email); + } } - } - - function get_duration($convert = false) - { - if ($this->duration !== null) + if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author')) { - if ($convert) + $name = null; + $url = null; + $email = null; + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) { - $time = SimplePie_Misc::time_hms($this->duration); - return $time; + $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - else + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) { - return $this->duration; + $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])); + } + if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $authors[] = new $this->item->feed->author_class($name, $url, $email); } } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author) + { + $authors[] = new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author) + { + $authors[] = new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author) + { + $authors[] = new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null); + } + + if (!empty($authors)) + { + return SimplePie_Misc::array_unique($authors); + } else { return null; } } - function get_expression() + function get_contributor($key = 0) { - if ($this->expression !== null) + $contributors = $this->get_contributors(); + if (isset($contributors[$key])) { - return $this->expression; + return $contributors[$key]; } else { - return 'full'; + return null; } } - function get_extension() + function get_contributors() { - if ($this->link !== null) + $contributors = array(); + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor) { - $url = SimplePie_Misc::parse_url($this->link); - if ($url['path'] !== '') + $name = null; + $uri = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) { - return pathinfo($url['path'], PATHINFO_EXTENSION); + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) + { + $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])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $uri !== null) + { + $contributors[] = new $this->item->feed->author_class($name, $uri, $email); + } + } + foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor) + { + $name = null; + $url = null; + $email = null; + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) + { + $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) + { + $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])); + } + if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) + { + $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + if ($name !== null || $email !== null || $url !== null) + { + $contributors[] = new $this->item->feed->author_class($name, $url, $email); } } - return null; - } - function get_framerate() - { - if ($this->framerate !== null) + if (!empty($contributors)) { - return $this->framerate; + return SimplePie_Misc::array_unique($contributors); } else { @@ -5499,17 +6030,12 @@ class SimplePie_Enclosure } } - function get_handler() - { - return $this->get_real_type(true); - } - - function get_hash($key = 0) + function get_link($key = 0, $rel = 'alternate') { - $hashes = $this->get_hashes(); - if (isset($hashes[$key])) + $links = $this->get_links($rel); + if (isset($links[$key])) { - return $hashes[$key]; + return $links[$key]; } else { @@ -5517,11 +6043,81 @@ class SimplePie_Enclosure } } - function get_hashes() + /** + * Added for parity between the parent-level and the item/entry-level. + */ + function get_permalink() { - if ($this->hashes !== null) + return $this->get_link(0); + } + + function get_links($rel = 'alternate') + { + if (!isset($this->data['links'])) { - return $this->hashes; + $this->data['links'] = array(); + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link')) + { + foreach ($links as $link) + { + if (isset($link['attribs']['']['href'])) + { + $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; + $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + } + } + } + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link')) + { + foreach ($links as $link) + { + if (isset($link['attribs']['']['href'])) + { + $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; + $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); + + } + } + } + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link')) + { + $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); + } + + $keys = array_keys($this->data['links']); + foreach ($keys as $key) + { + if (SimplePie_Misc::is_isegment_nz_nc($key)) + { + if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key])) + { + $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]); + $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]; + } + else + { + $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key]; + } + } + elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY) + { + $this->data['links'][substr($key, 41)] =& $this->data['links'][$key]; + } + $this->data['links'][$key] = array_unique($this->data['links'][$key]); + } + } + + if (isset($this->data['links'][$rel])) + { + return $this->data['links'][$rel]; } else { @@ -5529,60 +6125,43 @@ class SimplePie_Enclosure } } - function get_height() + function get_description() { - if ($this->height !== null) + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle')) { - return $this->height; + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); } - else + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline')) { - return null; + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); } - } - - function get_language() - { - if ($this->lang !== null) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description')) { - return $this->lang; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - else + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description')) { - return null; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - } - - function get_keyword($key = 0) - { - $keywords = $this->get_keywords(); - if (isset($keywords[$key])) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description')) { - return $keywords[$key]; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } - else + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description')) { - return null; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - } - - function get_keywords() - { - if ($this->keywords !== null) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description')) { - return $this->keywords; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - else + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary')) { - return null; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); } - } - - function get_length() - { - if ($this->length !== null) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle')) { - return $this->length; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); } else { @@ -5590,35 +6169,27 @@ class SimplePie_Enclosure } } - function get_link() + function get_copyright() { - if ($this->link !== null) + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights')) { - return urldecode($this->link); + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0])); } - else + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright')) { - return null; + return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0])); } - } - - function get_medium() - { - if ($this->medium !== null) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright')) { - return $this->medium; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - else + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights')) { - return null; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } - } - - function get_player() - { - if ($this->player !== null) + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights')) { - return $this->player; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); } else { @@ -5626,12 +6197,23 @@ class SimplePie_Enclosure } } - function get_rating($key = 0) + function get_language() { - $ratings = $this->get_ratings(); - if (isset($ratings[$key])) + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language')) { - return $ratings[$key]; + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); + } + elseif (isset($this->data['xml_lang'])) + { + return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT); } else { @@ -5639,11 +6221,15 @@ class SimplePie_Enclosure } } - function get_ratings() + function get_latitude() { - if ($this->ratings !== null) + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat')) { - return $this->ratings; + return (float) $return[0]['data']; + } + 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)) + { + return (float) $match[1]; } else { @@ -5651,12 +6237,19 @@ class SimplePie_Enclosure } } - function get_restriction($key = 0) + function get_longitude() { - $restrictions = $this->get_restrictions(); - if (isset($restrictions[$key])) + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long')) { - return $restrictions[$key]; + return (float) $return[0]['data']; + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon')) + { + return (float) $return[0]['data']; + } + 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)) + { + return (float) $match[2]; } else { @@ -5664,23 +6257,52 @@ class SimplePie_Enclosure } } - function get_restrictions() + function get_image_url() { - if ($this->restrictions !== null) + if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image')) { - return $this->restrictions; + return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); + } + elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon')) + { + return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); } else { return null; } } +} - function get_sampling_rate() +class SimplePie_Author +{ + var $name; + var $link; + var $email; + + // Constructor, used to input the data + function SimplePie_Author($name = null, $link = null, $email = null) { - if ($this->samplingrate !== null) + $this->name = $name; + $this->link = $link; + $this->email = $email; + } + + function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } + + function get_name() + { + if ($this->name !== null) { - return $this->samplingrate; + return $this->name; } else { @@ -5688,12 +6310,11 @@ class SimplePie_Enclosure } } - function get_size() + function get_link() { - $length = $this->get_length(); - if ($length !== null) + if ($this->link !== null) { - return round($length/1048576, 2); + return $this->link; } else { @@ -5701,24 +6322,44 @@ class SimplePie_Enclosure } } - function get_thumbnail($key = 0) + function get_email() { - $thumbnails = $this->get_thumbnails(); - if (isset($thumbnails[$key])) + if ($this->email !== null) { - return $thumbnails[$key]; + return $this->email; } else { return null; } } +} - function get_thumbnails() +class SimplePie_Category +{ + var $term; + var $scheme; + var $label; + + // Constructor, used to input the data + function SimplePie_Category($term = null, $scheme = null, $label = null) { - if ($this->thumbnails !== null) + $this->term = $term; + $this->scheme = $scheme; + $this->label = $label; + } + + function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } + + function get_term() + { + if ($this->term !== null) { - return $this->thumbnails; + return $this->term; } else { @@ -5726,11 +6367,11 @@ class SimplePie_Enclosure } } - function get_title() + function get_scheme() { - if ($this->title !== null) + if ($this->scheme !== null) { - return $this->title; + return $this->scheme; } else { @@ -5738,23 +6379,98 @@ class SimplePie_Enclosure } } - function get_type() + function get_label() { - if ($this->type !== null) + if ($this->label !== null) { - return $this->type; + return $this->label; } else { - return null; + return $this->get_term(); } } +} - function get_width() +class SimplePie_Enclosure +{ + var $bitrate; + var $captions; + var $categories; + var $channels; + var $copyright; + var $credits; + var $description; + var $duration; + var $expression; + var $framerate; + var $handler; + var $hashes; + var $height; + var $javascript; + var $keywords; + var $lang; + var $length; + var $link; + var $medium; + var $player; + var $ratings; + var $restrictions; + var $samplingrate; + var $thumbnails; + var $title; + var $type; + var $width; + + // Constructor, used to input the data + 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) { - if ($this->width !== null) + $this->bitrate = $bitrate; + $this->captions = $captions; + $this->categories = $categories; + $this->channels = $channels; + $this->copyright = $copyright; + $this->credits = $credits; + $this->description = $description; + $this->duration = $duration; + $this->expression = $expression; + $this->framerate = $framerate; + $this->hashes = $hashes; + $this->height = $height; + $this->javascript = $javascript; + $this->keywords = $keywords; + $this->lang = $lang; + $this->length = $length; + $this->link = $link; + $this->medium = $medium; + $this->player = $player; + $this->ratings = $ratings; + $this->restrictions = $restrictions; + $this->samplingrate = $samplingrate; + $this->thumbnails = $thumbnails; + $this->title = $title; + $this->type = $type; + $this->width = $width; + if (class_exists('idna_convert')) { - return $this->width; + $idn = new idna_convert; + $parsed = SimplePie_Misc::parse_url($link); + $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']); + } + $this->handler = $this->get_handler(); // Needs to load last + } + + function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } + + function get_bitrate() + { + if ($this->bitrate !== null) + { + return $this->bitrate; } else { @@ -5762,471 +6478,185 @@ class SimplePie_Enclosure } } - function native_embed($options='') + function get_caption($key = 0) { - return $this->embed($options, true); + $captions = $this->get_captions(); + if (isset($captions[$key])) + { + return $captions[$key]; + } + else + { + return null; + } } - /** - * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'. - */ - function embed($options = '', $native = false) + function get_captions() { - // Set up defaults - $audio = ''; - $video = ''; - $alt = ''; - $altclass = ''; - $loop = 'false'; - $width = 'auto'; - $height = 'auto'; - $bgcolor = '#ffffff'; - $mediaplayer = ''; - $widescreen = false; - $handler = $this->get_handler(); - $type = $this->get_real_type(); - - // Process options and reassign values as necessary - if (is_array($options)) + if ($this->captions !== null) { - extract($options); + return $this->captions; } else { - $options = explode(',', $options); - foreach($options as $option) - { - $opt = explode(':', $option, 2); - if (isset($opt[0], $opt[1])) - { - $opt[0] = trim($opt[0]); - $opt[1] = trim($opt[1]); - switch ($opt[0]) - { - case 'audio': - $audio = $opt[1]; - break; + return null; + } + } - case 'video': - $video = $opt[1]; - break; - - case 'alt': - $alt = $opt[1]; - break; - - case 'altclass': - $altclass = $opt[1]; - break; - - case 'loop': - $loop = $opt[1]; - break; - - case 'width': - $width = $opt[1]; - break; - - case 'height': - $height = $opt[1]; - break; - - case 'bgcolor': - $bgcolor = $opt[1]; - break; - - case 'mediaplayer': - $mediaplayer = $opt[1]; - break; - - case 'widescreen': - $widescreen = $opt[1]; - break; - } - } - } + function get_category($key = 0) + { + $categories = $this->get_categories(); + if (isset($categories[$key])) + { + return $categories[$key]; } - - $mime = explode('/', $type, 2); - $mime = $mime[0]; - - // Process values for 'auto' - if ($width == 'auto') + else { - if ($mime == 'video') - { - if ($height == 'auto') - { - $width = 480; - } - elseif ($widescreen) - { - $width = round((intval($height)/9)*16); - } - else - { - $width = round((intval($height)/3)*4); - } - } - else - { - $width = '100%'; - } + return null; } + } - if ($height == 'auto') + function get_categories() + { + if ($this->categories !== null) { - if ($mime == 'audio') - { - $height = 0; - } - elseif ($mime == 'video') - { - if ($width == 'auto') - { - if ($widescreen) - { - $height = 270; - } - else - { - $height = 360; - } - } - elseif ($widescreen) - { - $height = round((intval($width)/16)*9); - } - else - { - $height = round((intval($width)/4)*3); - } - } - else - { - $height = 376; - } + return $this->categories; } - elseif ($mime == 'audio') + else { - $height = 0; + return null; } + } - // Set proper placeholder value - if ($mime == 'audio') + function get_channels() + { + if ($this->channels !== null) { - $placeholder = $audio; + return $this->channels; } - elseif ($mime == 'video') + else { - $placeholder = $video; + return null; } + } - $embed = ''; - - // Make sure the JS library is included - if (!$native) + function get_copyright() + { + if ($this->copyright !== null) { - static $javascript_outputted = null; - if (!$javascript_outputted && $this->javascript) - { - $embed .= ''; - $javascript_outputted = true; - } + return $this->copyright; } - - // Odeo Feed MP3's - if ($handler == 'odeo') + else { - if ($native) - { - $embed .= ''; - } - else - { - $embed .= ''; - } + return null; } + } - // Flash - elseif ($handler == 'flash') + function get_credit($key = 0) + { + $credits = $this->get_credits(); + if (isset($credits[$key])) { - if ($native) - { - $embed .= "get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\">"; - } - else - { - $embed .= ""; - } + return $credits[$key]; + } + else + { + return null; } + } - // Flash Media Player file types. - // Preferred handler for MP3 file types. - elseif ($handler == 'fmedia' || ($handler == 'mp3' && $mediaplayer != '')) + function get_credits() + { + if ($this->credits !== null) { - $height += 20; - if ($native) - { - $embed .= "get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\">"; - } - else - { - $embed .= ""; - } + return $this->credits; + } + else + { + return null; } + } - // QuickTime 7 file types. Need to test with QuickTime 6. - // Only handle MP3's if the Flash Media Player is not present. - elseif ($handler == 'quicktime' || ($handler == 'mp3' && $mediaplayer == '')) + function get_description() + { + if ($this->description !== null) { - $height += 16; - if ($native) - { - if ($placeholder != ""){ - $embed .= "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/\">"; - } - else { - $embed .= "get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\">"; - } - } - else - { - $embed .= ""; - } + return $this->description; + } + else + { + return null; } + } - // Windows Media - elseif ($handler == 'wmedia') + function get_duration($convert = false) + { + if ($this->duration !== null) { - $height += 45; - if ($native) + if ($convert) { - $embed .= "get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\">"; + $time = SimplePie_Misc::time_hms($this->duration); + return $time; } else { - $embed .= ""; + return $this->duration; } } - - // Everything else - else $embed .= '' . $alt . ''; - - return $embed; - } - - function get_real_type($find_handler = false) - { - // If it's Odeo, let's get it out of the way. - if (substr(strtolower($this->get_link()), 0, 15) == 'http://odeo.com') + else { - return 'odeo'; + return null; } + } - // Mime-types by handler. - $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash - $types_fmedia = array('video/flv', 'video/x-flv'); // Flash Media Player - $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 - $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 - $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3 - - if ($this->get_type() !== null) + function get_expression() + { + if ($this->expression !== null) { - $type = strtolower($this->type); + return $this->expression; } else { - $type = null; + return 'full'; } + } - // If we encounter an unsupported mime-type, check the file extension and guess intelligently. - if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3))) + function get_extension() + { + if ($this->link !== null) { - switch (strtolower($this->get_extension())) + $url = SimplePie_Misc::parse_url($this->link); + if ($url['path'] !== '') { - // Audio mime-types - case 'aac': - case 'adts': - $type = 'audio/acc'; - break; - - case 'aif': - case 'aifc': - case 'aiff': - case 'cdda': - $type = 'audio/aiff'; - break; - - case 'bwf': - $type = 'audio/wav'; - break; - - case 'kar': - case 'mid': - case 'midi': - case 'smf': - $type = 'audio/midi'; - break; - - case 'm4a': - $type = 'audio/x-m4a'; - break; - - case 'mp3': - case 'swa': - $type = 'audio/mp3'; - break; - - case 'wav': - $type = 'audio/wav'; - break; - - case 'wax': - $type = 'audio/x-ms-wax'; - break; - - case 'wma': - $type = 'audio/x-ms-wma'; - break; - - // Video mime-types - case '3gp': - case '3gpp': - $type = 'video/3gpp'; - break; - - case '3g2': - case '3gp2': - $type = 'video/3gpp2'; - break; - - case 'asf': - $type = 'video/x-ms-asf'; - break; - - case 'flv': - $type = 'video/x-flv'; - break; - - case 'm1a': - case 'm1s': - case 'm1v': - case 'm15': - case 'm75': - case 'mp2': - case 'mpa': - case 'mpeg': - case 'mpg': - case 'mpm': - case 'mpv': - $type = 'video/mpeg'; - break; - - case 'm4v': - $type = 'video/x-m4v'; - break; - - case 'mov': - case 'qt': - $type = 'video/quicktime'; - break; - - case 'mp4': - case 'mpg4': - $type = 'video/mp4'; - break; - - case 'sdv': - $type = 'video/sd-video'; - break; - - case 'wm': - $type = 'video/x-ms-wm'; - break; - - case 'wmv': - $type = 'video/x-ms-wmv'; - break; - - case 'wvx': - $type = 'video/x-ms-wvx'; - break; - - // Flash mime-types - case 'spl': - $type = 'application/futuresplash'; - break; - - case 'swf': - $type = 'application/x-shockwave-flash'; - break; + return pathinfo($url['path'], PATHINFO_EXTENSION); } } + return null; + } - if ($find_handler) + function get_framerate() + { + if ($this->framerate !== null) { - if (in_array($type, $types_flash)) - { - return 'flash'; - } - elseif (in_array($type, $types_fmedia)) - { - return 'fmedia'; - } - elseif (in_array($type, $types_quicktime)) - { - return 'quicktime'; - } - elseif (in_array($type, $types_wmedia)) - { - return 'wmedia'; - } - elseif (in_array($type, $types_mp3)) - { - return 'mp3'; - } - else - { - return null; - } + return $this->framerate; } else { - return $type; + return null; } } -} - -class SimplePie_Caption -{ - var $type; - var $lang; - var $startTime; - var $endTime; - var $text; - - // Constructor, used to input the data - function SimplePie_Caption($type = null, $lang = null, $startTime = null, $endTime = null, $text = null) - { - $this->type = $type; - $this->lang = $lang; - $this->startTime = $startTime; - $this->endTime = $endTime; - $this->text = $text; - } - function __toString() + function get_handler() { - // There is no $this->data here - return md5(serialize($this)); + return $this->get_real_type(true); } - function get_endtime() + function get_hash($key = 0) { - if ($this->endTime !== null) + $hashes = $this->get_hashes(); + if (isset($hashes[$key])) { - return $this->endTime; + return $hashes[$key]; } else { @@ -6234,11 +6664,11 @@ class SimplePie_Caption } } - function get_language() + function get_hashes() { - if ($this->language !== null) + if ($this->hashes !== null) { - return $this->language; + return $this->hashes; } else { @@ -6246,11 +6676,11 @@ class SimplePie_Caption } } - function get_starttime() + function get_height() { - if ($this->startTime !== null) + if ($this->height !== null) { - return $this->startTime; + return $this->height; } else { @@ -6258,11 +6688,11 @@ class SimplePie_Caption } } - function get_text() + function get_language() { - if ($this->text !== null) + if ($this->lang !== null) { - return $this->text; + return $this->lang; } else { @@ -6270,44 +6700,48 @@ class SimplePie_Caption } } - function get_type() + function get_keyword($key = 0) { - if ($this->type !== null) + $keywords = $this->get_keywords(); + if (isset($keywords[$key])) { - return $this->type; + return $keywords[$key]; } else { return null; } } -} -class SimplePie_Credit -{ - var $role; - var $scheme; - var $name; - - // Constructor, used to input the data - function SimplePie_Credit($role = null, $scheme = null, $name = null) + function get_keywords() { - $this->role = $role; - $this->scheme = $scheme; - $this->name = $name; + if ($this->keywords !== null) + { + return $this->keywords; + } + else + { + return null; + } } - function __toString() + function get_length() { - // There is no $this->data here - return md5(serialize($this)); + if ($this->length !== null) + { + return $this->length; + } + else + { + return null; + } } - function get_role() + function get_link() { - if ($this->role !== null) + if ($this->link !== null) { - return $this->role; + return urldecode($this->link); } else { @@ -6315,11 +6749,11 @@ class SimplePie_Credit } } - function get_scheme() + function get_medium() { - if ($this->scheme !== null) + if ($this->medium !== null) { - return $this->scheme; + return $this->medium; } else { @@ -6327,42 +6761,24 @@ class SimplePie_Credit } } - function get_name() + function get_player() { - if ($this->name !== null) + if ($this->player !== null) { - return $this->name; + return $this->player; } else { return null; } } -} - -class SimplePie_Copyright -{ - var $url; - var $label; - // Constructor, used to input the data - function SimplePie_Copyright($url = null, $label = null) - { - $this->url = $url; - $this->label = $label; - } - - function __toString() - { - // There is no $this->data here - return md5(serialize($this)); - } - - function get_url() + function get_rating($key = 0) { - if ($this->url !== null) + $ratings = $this->get_ratings(); + if (isset($ratings[$key])) { - return $this->url; + return $ratings[$key]; } else { @@ -6370,42 +6786,48 @@ class SimplePie_Copyright } } - function get_attribution() + function get_ratings() { - if ($this->label !== null) + if ($this->ratings !== null) { - return $this->label; + return $this->ratings; } else { return null; } } -} - -class SimplePie_Rating -{ - var $scheme; - var $value; - // Constructor, used to input the data - function SimplePie_Rating($scheme = null, $value = null) + function get_restriction($key = 0) { - $this->scheme = $scheme; - $this->value = $value; + $restrictions = $this->get_restrictions(); + if (isset($restrictions[$key])) + { + return $restrictions[$key]; + } + else + { + return null; + } } - function __toString() + function get_restrictions() { - // There is no $this->data here - return md5(serialize($this)); + if ($this->restrictions !== null) + { + return $this->restrictions; + } + else + { + return null; + } } - function get_scheme() + function get_sampling_rate() { - if ($this->scheme !== null) + if ($this->samplingrate !== null) { - return $this->scheme; + return $this->samplingrate; } else { @@ -6413,44 +6835,49 @@ class SimplePie_Rating } } - function get_value() + function get_size() { - if ($this->value !== null) + $length = $this->get_length(); + if ($length !== null) { - return $this->value; + return round($length/1048576, 2); } else { return null; } } -} -class SimplePie_Restriction -{ - var $relationship; - var $type; - var $value; - - // Constructor, used to input the data - function SimplePie_Restriction($relationship = null, $type = null, $value = null) + function get_thumbnail($key = 0) { - $this->relationship = $relationship; - $this->type = $type; - $this->value = $value; + $thumbnails = $this->get_thumbnails(); + if (isset($thumbnails[$key])) + { + return $thumbnails[$key]; + } + else + { + return null; + } } - function __toString() + function get_thumbnails() { - // There is no $this->data here - return md5(serialize($this)); + if ($this->thumbnails !== null) + { + return $this->thumbnails; + } + else + { + return null; + } } - function get_relationship() + function get_title() { - if ($this->relationship !== null) + if ($this->title !== null) { - return $this->relationship; + return $this->title; } else { @@ -6470,3352 +6897,6923 @@ class SimplePie_Restriction } } - function get_value() + function get_width() { - if ($this->value !== null) + if ($this->width !== null) { - return $this->value; + return $this->width; } else { return null; } } -} -/** - * @todo Move to properly supporting RFC2616 (HTTP/1.1) - */ -class SimplePie_File -{ - var $url; - var $useragent; - var $success = true; - var $headers = array(); - var $body; - var $status_code; - var $redirects = 0; - var $error; - var $method; + function native_embed($options='') + { + return $this->embed($options, true); + } - function SimplePie_File($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) + /** + * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'. + */ + function embed($options = '', $native = false) { - if (class_exists('idna_convert')) + // Set up defaults + $audio = ''; + $video = ''; + $alt = ''; + $altclass = ''; + $loop = 'false'; + $width = 'auto'; + $height = 'auto'; + $bgcolor = '#ffffff'; + $mediaplayer = ''; + $widescreen = false; + $handler = $this->get_handler(); + $type = $this->get_real_type(); + + // Process options and reassign values as necessary + if (is_array($options)) { - $idn = new idna_convert; - $parsed = SimplePie_Misc::parse_url($url); - $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']); + extract($options); } - $this->url = $url; - $this->useragent = $useragent; - if (preg_match('/^http(s)?:\/\//i', $url)) + else { - if ($useragent === null) - { - $useragent = ini_get('user_agent'); - $this->useragent = $useragent; - } - if (!is_array($headers)) + $options = explode(',', $options); + foreach($options as $option) { - $headers = array(); + $opt = explode(':', $option, 2); + if (isset($opt[0], $opt[1])) + { + $opt[0] = trim($opt[0]); + $opt[1] = trim($opt[1]); + switch ($opt[0]) + { + case 'audio': + $audio = $opt[1]; + break; + + case 'video': + $video = $opt[1]; + break; + + case 'alt': + $alt = $opt[1]; + break; + + case 'altclass': + $altclass = $opt[1]; + break; + + case 'loop': + $loop = $opt[1]; + break; + + case 'width': + $width = $opt[1]; + break; + + case 'height': + $height = $opt[1]; + break; + + case 'bgcolor': + $bgcolor = $opt[1]; + break; + + case 'mediaplayer': + $mediaplayer = $opt[1]; + break; + + case 'widescreen': + $widescreen = $opt[1]; + break; + } + } } - if (!$force_fsockopen && extension_loaded('curl')) + } + + $mime = explode('/', $type, 2); + $mime = $mime[0]; + + // Process values for 'auto' + if ($width === 'auto') + { + if ($mime === 'video') { - $this->method = 'curl'; - $fp = curl_init(); - $headers2 = array(); - foreach ($headers as $key => $value) + if ($height === 'auto') { - $headers2[] = "$key: $value"; + $width = 480; } - if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>=')) + elseif ($widescreen) { - curl_setopt($fp, CURLOPT_ENCODING, ''); + $width = round((intval($height)/9)*16); } - curl_setopt($fp, CURLOPT_URL, $url); - curl_setopt($fp, CURLOPT_HEADER, 1); - curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($fp, CURLOPT_TIMEOUT, $timeout); - curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout); - curl_setopt($fp, CURLOPT_REFERER, $url); - curl_setopt($fp, CURLOPT_USERAGENT, $useragent); - curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2); - if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>=')) + else { - curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1); - curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects); - } - - $this->headers = curl_exec($fp); - if (curl_errno($fp) == 23 || curl_errno($fp) == 61) - { - curl_setopt($fp, CURLOPT_ENCODING, 'none'); - $this->headers = curl_exec($fp); - } - if (curl_errno($fp)) - { - $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp); - $this->success = false; - } - else - { - $info = curl_getinfo($fp); - curl_close($fp); - $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1); - $this->headers = array_pop($this->headers); - $parser = new SimplePie_HTTP_Parser($this->headers); - if ($parser->parse()) - { - $this->headers = $parser->headers; - $this->body = $parser->body; - $this->status_code = $parser->status_code; - if (($this->status_code == 300 || $this->status_code == 301 || $this->status_code == 302 || $this->status_code == 303 || $this->status_code == 307 || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) - { - $this->redirects++; - if (isset($this->headers['content-location'])) - { - $location = SimplePie_Misc::absolutize_url($this->headers['location'], SimplePie_Misc::absolutize_url($this->headers['content-location'], $url)); - } - else - { - $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); - } - return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen); - } - } + $width = round((intval($height)/3)*4); } } else { - $this->method = 'fsockopen'; - $url_parts = parse_url($url); - if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) == 'https') - { - $url_parts['host'] = "ssl://$url_parts[host]"; - $url_parts['port'] = 443; - } - if (!isset($url_parts['port'])) - { - $url_parts['port'] = 80; - } - $fp = fsockopen($url_parts['host'], $url_parts['port'], $errno, $errstr, $timeout); - if (!$fp) - { - $this->error = 'fsockopen error: ' . $errstr; - $this->success = false; - } - else + $width = '100%'; + } + } + + if ($height === 'auto') + { + if ($mime === 'audio') + { + $height = 0; + } + elseif ($mime === 'video') + { + if ($width === 'auto') { - if (function_exists('stream_set_timeout')) - { - stream_set_timeout($fp, $timeout); - } - else - { - socket_set_timeout($fp, $timeout); - } - if (isset($url_parts['path'])) + if ($widescreen) { - if (isset($url_parts['query'])) - { - $get = "$url_parts[path]?$url_parts[query]"; - } - else - { - $get = $url_parts['path']; - } + $height = 270; } else { - $get = '/'; - } - $out = "GET $get HTTP/1.0\r\n"; - $out .= "Host: $url_parts[host]\r\n"; - $out .= "User-Agent: $useragent\r\n"; - if (function_exists('gzinflate')) - { - $out .= "Accept-Encoding: gzip,deflate\r\n"; + $height = 360; } + } + elseif ($widescreen) + { + $height = round((intval($width)/16)*9); + } + else + { + $height = round((intval($width)/4)*3); + } + } + else + { + $height = 376; + } + } + elseif ($mime === 'audio') + { + $height = 0; + } - if (isset($url_parts['user']) && isset($url_parts['pass'])) - { - $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n"; - } - foreach ($headers as $key => $value) - { - $out .= "$key: $value\r\n"; - } - $out .= "Connection: Close\r\n\r\n"; - fwrite($fp, $out); + // Set proper placeholder value + if ($mime === 'audio') + { + $placeholder = $audio; + } + elseif ($mime === 'video') + { + $placeholder = $video; + } - if (function_exists('stream_get_meta_data')) - { - $info = stream_get_meta_data($fp); - } - else - { - $info = socket_get_status($fp); - } + $embed = ''; - $this->headers = ''; - while (!$info['eof'] && !$info['timed_out']) - { - $this->headers .= fread($fp, 1160); - if (function_exists('stream_get_meta_data')) - { - $info = stream_get_meta_data($fp); - } - else - { - $info = socket_get_status($fp); - } - } - if (!$info['timed_out']) - { - $parser = new SimplePie_HTTP_Parser($this->headers); - if ($parser->parse()) - { - $this->headers = $parser->headers; - $this->body = $parser->body; - $this->status_code = $parser->status_code; - if (($this->status_code == 300 || $this->status_code == 301 || $this->status_code == 302 || $this->status_code == 303 || $this->status_code == 307 || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) - { - $this->redirects++; - if (isset($this->headers['content-location'])) - { - $location = SimplePie_Misc::absolutize_url($this->headers['location'], SimplePie_Misc::absolutize_url($this->headers['content-location'], $url)); - } - else - { - $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); - } - return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen); - } - if (isset($this->headers['content-encoding']) && ($this->headers['content-encoding'] == 'gzip' || $this->headers['content-encoding'] == 'deflate')) - { - if (substr($this->body, 0, 8) == "\x1f\x8b\x08\x00\x00\x00\x00\x00") - { - $this->body = substr($this->body, 10); - } - $this->body = gzinflate($this->body); - } - } - } - else - { - $this->error = 'fsocket timed out'; - $this->success = false; - } - fclose($fp); - } + // Make sure the JS library is included + if (!$native) + { + static $javascript_outputted = null; + if (!$javascript_outputted && $this->javascript) + { + $embed .= ''; + $javascript_outputted = true; } } - elseif (function_exists('file_get_contents')) + + // Odeo Feed MP3's + if ($handler === 'odeo') { - $this->method = 'file_get_contents'; - if (!$this->body = file_get_contents($url)) + if ($native) { - $this->error = 'file_get_contents could not read the file'; - $this->success = false; + $embed .= ''; + } + else + { + $embed .= ''; } } - else + + // Flash + elseif ($handler === 'flash') { - $this->method = 'fopen'; - if (($fp = fopen($url, 'rb')) === false) + if ($native) { - $this->error = 'failed to open stream: No such file or directory'; - $this->success = false; + $embed .= "get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\">"; + } + else + { + $embed .= ""; + } + } + + // Flash Media Player file types. + // Preferred handler for MP3 file types. + elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== '')) + { + $height += 20; + if ($native) + { + $embed .= "get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\">"; } else { - $this->body = ''; - while (!feof($fp)) + $embed .= ""; + } + } + + // QuickTime 7 file types. Need to test with QuickTime 6. + // Only handle MP3's if the Flash Media Player is not present. + elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === '')) + { + $height += 16; + if ($native) + { + if ($placeholder !== '') { - $this->body .= fread($fp, 8192); + $embed .= "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/\">"; + } + else + { + $embed .= "get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\">"; } - fclose($fp); + } + else + { + $embed .= ""; } } - } -} -/** - * HTTP Response Parser - * - * @package SimplePie - * @todo Support HTTP Requests - */ -class SimplePie_HTTP_Parser -{ - /** - * HTTP Version - * - * @access public - * @var string - */ - var $http_version = ''; + // Windows Media + elseif ($handler === 'wmedia') + { + $height += 45; + if ($native) + { + $embed .= "get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\">"; + } + else + { + $embed .= ""; + } + } - /** - * Status code - * - * @access public - * @var string - */ - var $status_code = ''; + // Everything else + else $embed .= '' . $alt . ''; - /** - * Reason phrase - * - * @access public - * @var string - */ - var $reason = ''; - - /** - * Key/value pairs of the headers - * - * @access public - * @var array - */ - var $headers = array(); - - /** - * Body of the response - * - * @access public - * @var string - */ - var $body = ''; - - /** - * Current state of the state machine - * - * @access private - * @var string - */ - var $state = 'start'; - - /** - * Input data - * - * @access private - * @var string - */ - var $data = ''; - - /** - * Input data length (to avoid calling strlen() everytime this is needed) - * - * @access private - * @var int - */ - var $data_length = 0; - - /** - * Current position of the pointer - * - * @access private - * @var int - */ - var $position = 0; - - /** - * Name of the hedaer currently being parsed - * - * @access private - * @var string - */ - var $name = ''; - - /** - * Value of the hedaer currently being parsed - * - * @access private - * @var string - */ - var $value = ''; - - /** - * Create an instance of the class with the input data - * - * @access public - * @param string $data Input data - */ - function SimplePie_HTTP_Parser($data) - { - $this->data = $data; - $this->data_length = strlen($this->data); + return $embed; } - /** - * Parse the input data - * - * @access public - * @return bool true on success, false on failure - */ - function parse() + function get_real_type($find_handler = false) { - while ($this->state && $this->state != 'emit' && $this->has_data()) - { - $state = $this->state; - $this->$state(); - } - $this->data = ''; - if ($this->state == 'emit') - { - return true; - } - else + // If it's Odeo, let's get it out of the way. + if (substr(strtolower($this->get_link()), 0, 15) === 'http://odeo.com') { - $this->http_version = ''; - $this->status_code = ''; - $this->headers = array(); - $this->body = ''; - return false; + return 'odeo'; } - } - - /** - * Check whether there is data beyond the pointer - * - * @access private - * @return bool true if there is further data, false if not - */ - function has_data() - { - return (bool) ($this->position < $this->data_length); - } - - /** - * See if the next character is LWS - * - * @access private - * @return bool true if the next character is LWS, false if not - */ - function is_linear_whitespace() - { - return (bool) (strspn($this->data, "\x09\x20", $this->position, 1) - || (substr($this->data, $this->position, 2) == "\r\n" && strspn($this->data, "\x09\x20", $this->position + 2, 1)) - || (strspn($this->data, "\r\n", $this->position, 1) && strspn($this->data, "\x09\x20", $this->position + 1, 1))); - } - /** - * The starting state of the state machine, see if the data is a response or request - * - * @access private - */ - function start() - { - $this->state = 'http_version_response'; - } + // Mime-types by handler. + $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash + $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player + $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 + $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 + $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3 - /** - * Parse an HTTP-version string - * - * @access private - */ - function http_version() - { - if (preg_match('/^HTTP\/([0-9]+\.[0-9]+)/i', substr($this->data, $this->position, strcspn($this->data, "\r\n", $this->position)), $match)) + if ($this->get_type() !== null) { - $this->position += strlen($match[0]); - $this->http_version = $match[1]; - return true; + $type = strtolower($this->type); } else { - return false; + $type = null; } - } - /** - * Parse LWS, replacing consecutive characters with a single space - * - * @access private - */ - function linear_whitespace() - { - do + // If we encounter an unsupported mime-type, check the file extension and guess intelligently. + if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3))) { - if (substr($this->data, $this->position, 2) == "\r\n") - { - $this->position += 2; - } - elseif (strspn($this->data, "\r\n", $this->position, 1)) + switch (strtolower($this->get_extension())) { - $this->position++; - } - $this->position += strspn($this->data, "\x09\x20", $this->position); - } while ($this->is_linear_whitespace()); - $this->value .= "\x20"; - } + // Audio mime-types + case 'aac': + case 'adts': + $type = 'audio/acc'; + break; - /** - * Parse an HTTP-version string within a response - * - * @access private - */ - function http_version_response() - { - if ($this->http_version() && $this->data[$this->position] == "\x20") - { - $this->state = 'status_code'; - $this->position++; - } - else - { - $this->state = false; - } - } + case 'aif': + case 'aifc': + case 'aiff': + case 'cdda': + $type = 'audio/aiff'; + break; - /** - * Parse a status code - * - * @access private - */ - function status_code() - { - if (strspn($this->data, '1234567890', $this->position, 3) == 3) - { - $this->status_code = substr($this->data, $this->position, 3); - $this->state = 'reason_phrase'; - $this->position += 3; - } - else - { - $this->state = false; - } - } + case 'bwf': + $type = 'audio/wav'; + break; - /** - * Skip over the reason phrase (it has no normative value, and you can send absolutely anything here) - * - * @access private - */ - function reason_phrase() - { - $len = strcspn($this->data, "\r\n", $this->position); - $this->reason = substr($this->data, $this->position, $len); - $this->position += $len; - if ($this->has_data()) - { - if (substr($this->data, $this->position, 2) == "\r\n") - { - $this->position += 2; - } - elseif (strspn($this->data, "\r\n", $this->position, 1)) - { - $this->position++; - } - $this->state = 'name'; - } - } + case 'kar': + case 'mid': + case 'midi': + case 'smf': + $type = 'audio/midi'; + break; - /** - * Parse a header name - * - * @access private - */ - function name() - { - $len = strcspn($this->data, ':', $this->position); - $this->name = substr($this->data, $this->position, $len); - $this->position += $len; + case 'm4a': + $type = 'audio/x-m4a'; + break; - if ($this->has_data() && $this->data[$this->position] == ':') - { - $this->state = 'value_next'; - $this->position++; - } - else - { - $this->state = false; - } - } + case 'mp3': + case 'swa': + $type = 'audio/mp3'; + break; - /** - * See what state to move the state machine to while within non-quoted header values - * - * @access private - */ - function value_next() - { - if ($this->is_linear_whitespace()) - { - $this->state = 'value_linear_whitespace'; - } - elseif ($this->data[$this->position] == '"') - { - $this->state = 'value_quote_next'; - $this->position++; - } - elseif (substr($this->data, $this->position, 2) == "\r\n") - { - $this->state = 'end_crlf'; - $this->position += 2; + case 'wav': + $type = 'audio/wav'; + break; + + case 'wax': + $type = 'audio/x-ms-wax'; + break; + + case 'wma': + $type = 'audio/x-ms-wma'; + break; + + // Video mime-types + case '3gp': + case '3gpp': + $type = 'video/3gpp'; + break; + + case '3g2': + case '3gp2': + $type = 'video/3gpp2'; + break; + + case 'asf': + $type = 'video/x-ms-asf'; + break; + + case 'flv': + $type = 'video/x-flv'; + break; + + case 'm1a': + case 'm1s': + case 'm1v': + case 'm15': + case 'm75': + case 'mp2': + case 'mpa': + case 'mpeg': + case 'mpg': + case 'mpm': + case 'mpv': + $type = 'video/mpeg'; + break; + + case 'm4v': + $type = 'video/x-m4v'; + break; + + case 'mov': + case 'qt': + $type = 'video/quicktime'; + break; + + case 'mp4': + case 'mpg4': + $type = 'video/mp4'; + break; + + case 'sdv': + $type = 'video/sd-video'; + break; + + case 'wm': + $type = 'video/x-ms-wm'; + break; + + case 'wmv': + $type = 'video/x-ms-wmv'; + break; + + case 'wvx': + $type = 'video/x-ms-wvx'; + break; + + // Flash mime-types + case 'spl': + $type = 'application/futuresplash'; + break; + + case 'swf': + $type = 'application/x-shockwave-flash'; + break; + } } - elseif (strspn($this->data, "\r\n", $this->position, 1)) + + if ($find_handler) { - $this->state = 'end_crlf'; - $this->position++; + if (in_array($type, $types_flash)) + { + return 'flash'; + } + elseif (in_array($type, $types_fmedia)) + { + return 'fmedia'; + } + elseif (in_array($type, $types_quicktime)) + { + return 'quicktime'; + } + elseif (in_array($type, $types_wmedia)) + { + return 'wmedia'; + } + elseif (in_array($type, $types_mp3)) + { + return 'mp3'; + } + else + { + return null; + } } else { - $this->state = 'value_no_quote'; + return $type; } } +} - /** - * Parse a header value while outside quotes - * - * @access private - */ - function value_no_quote() +class SimplePie_Caption +{ + var $type; + var $lang; + var $startTime; + var $endTime; + var $text; + + // Constructor, used to input the data + function SimplePie_Caption($type = null, $lang = null, $startTime = null, $endTime = null, $text = null) { - $len = strcspn($this->data, "\x09\x20\r\n\"", $this->position); - $this->value .= substr($this->data, $this->position, $len); - $this->state = 'value_next'; - $this->position += $len; + $this->type = $type; + $this->lang = $lang; + $this->startTime = $startTime; + $this->endTime = $endTime; + $this->text = $text; } - /** - * Parse LWS outside quotes - * - * @access private - */ - function value_linear_whitespace() + function __toString() { - $this->linear_whitespace(); - $this->state = 'value_next'; + // There is no $this->data here + return md5(serialize($this)); } - /** - * See what state to move the state machine to while within quoted header values - * - * @access private - */ - function value_quote_next() + function get_endtime() { - if ($this->is_linear_whitespace()) + if ($this->endTime !== null) { - $this->state = 'value_linear_whitespace_quote'; + return $this->endTime; } else { - switch ($this->data[$this->position]) - { - case '"': - $this->state = 'value_next'; - $this->position++; - break; - - case '\\': - $this->state = 'value_quote_char'; - $this->position++; - break; - - default: - $this->state = 'value_quote'; - break; - } + return null; } } - /** - * Parse a header value while within quotes - * - * @access private - */ - function value_quote() - { - $len = strcspn($this->data, "\x09\x20\r\n\"\\", $this->position); - $this->value .= substr($this->data, $this->position, $len); - $this->position += $len; - $this->state = 'value_quote_next'; - } - - /** - * Parse an escaped character within quotes - * - * @access private - */ - function value_quote_char() + function get_language() { - $this->value .= $this->data[$this->position]; - $this->state = 'value_quote_next'; - $this->position++; + if ($this->lang !== null) + { + return $this->lang; + } + else + { + return null; + } } - /** - * Parse LWS within quotes - * - * @access private - */ - function value_linear_whitespace_quote() + function get_starttime() { - $this->linear_whitespace(); - $this->state = 'value_quote_next'; + if ($this->startTime !== null) + { + return $this->startTime; + } + else + { + return null; + } } - /** - * Parse a CRLF, and see whether we have a further header, or whether we are followed by the body - * - * @access private - */ - function end_crlf() + function get_text() { - $this->name = strtolower($this->name); - $this->value = trim($this->value, "\x20"); - if (isset($this->headers[$this->name])) + if ($this->text !== null) { - $this->headers[$this->name] .= ', ' . $this->value; + return $this->text; } else { - $this->headers[$this->name] = $this->value; + return null; } + } - if (substr($this->data, $this->position, 2) == "\r\n") - { - $this->body = substr($this->data, $this->position + 2); - $this->state = 'emit'; - } - elseif (strspn($this->data, "\r\n", $this->position, 1)) + function get_type() + { + if ($this->type !== null) { - $this->body = substr($this->data, $this->position + 1); - $this->state = 'emit'; + return $this->type; } else { - $this->name = ''; - $this->value = ''; - $this->state = 'name'; + return null; } } } -class SimplePie_Cache +class SimplePie_Credit { - var $location; - var $filename; - var $extension; + var $role; + var $scheme; var $name; - function SimplePie_Cache($location, $filename, $extension) + // Constructor, used to input the data + function SimplePie_Credit($role = null, $scheme = null, $name = null) { - $this->location = $location; - $this->filename = rawurlencode($filename); - $this->extension = rawurlencode($extension); - $this->name = "$location/$this->filename.$this->extension"; + $this->role = $role; + $this->scheme = $scheme; + $this->name = $name; } - function save($data) + function __toString() { - if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location)) + // There is no $this->data here + return md5(serialize($this)); + } + + function get_role() + { + if ($this->role !== null) { - if (function_exists('file_put_contents')) - { - return (bool) file_put_contents($this->name, serialize($data)); - } - else - { - $fp = fopen($this->name, 'wb'); - if ($fp) - { - fwrite($fp, serialize($data)); - fclose($fp); - return true; - } - } + return $this->role; } - return false; - } - - function load() - { - if (file_exists($this->name) && is_readable($this->name)) + else { - if (function_exists('file_get_contents')) - { - return unserialize(file_get_contents($this->name)); - } - elseif (($fp = fopen($this->name, 'rb')) !== false) - { - $data = ''; - while (!feof($fp)) - { - $data .= fread($fp, 8192); - } - fclose($fp); - return unserialize($data); - } + return null; } - return false; } - function mtime() + function get_scheme() { - if (file_exists($this->name)) + if ($this->scheme !== null) { - return filemtime($this->name); + return $this->scheme; } - return false; - } - - function touch() - { - if (file_exists($this->name)) + else { - return touch($this->name); + return null; } - return false; } - function unlink() + function get_name() { - if (file_exists($this->name)) + if ($this->name !== null) { - return unlink($this->name); + return $this->name; + } + else + { + return null; } - return false; } } -class SimplePie_Misc +class SimplePie_Copyright { - function time_hms($seconds) + var $url; + var $label; + + // Constructor, used to input the data + function SimplePie_Copyright($url = null, $label = null) { - $time = ''; + $this->url = $url; + $this->label = $label; + } - $hours = floor($seconds / 3600); - $remainder = $seconds % 3600; - if ($hours > 0) - { - $time .= $hours.':'; - } + function __toString() + { + // There is no $this->data here + return md5(serialize($this)); + } - $minutes = floor($remainder / 60); - $seconds = $remainder % 60; - if ($minutes < 10 && $hours > 0) + function get_url() + { + if ($this->url !== null) { - $minutes = '0' . $minutes; + return $this->url; } - if ($seconds < 10) + else { - $seconds = '0' . $seconds; + return null; } - - $time .= $minutes.':'; - $time .= $seconds; - - return $time; } - function absolutize_url($relative, $base) + function get_attribution() { - if ($relative !== '') + if ($this->label !== null) { - $relative = SimplePie_Misc::parse_url($relative); - if ($relative['scheme'] !== '') - { - $target = $relative; - } - elseif ($base !== '') - { - $base = SimplePie_Misc::parse_url($base); - $target = SimplePie_Misc::parse_url(''); - if ($relative['authority'] !== '') - { - $target = $relative; - $target['scheme'] = $base['scheme']; - } - else - { - $target['scheme'] = $base['scheme']; - $target['authority'] = $base['authority']; - if ($relative['path'] !== '') - { - if (strpos($relative['path'], '/') === 0) - { - $target['path'] = $relative['path']; - } - elseif (($target['path'] = dirname("$base[path].")) == '/') - { - $target['path'] .= $relative['path']; - } - else - { - $target['path'] .= '/' . $relative['path']; - } - if ($relative['query'] !== '') - { - $target['query'] = $relative['query']; - } - } - else - { - if ($base['path'] !== '') - { - $target['path'] = $base['path']; - } - else - { - $target['path'] = '/'; - } - if ($relative['query'] !== '') - { - $target['query'] = $relative['query']; - } - elseif ($base['query'] !== '') - { - $target['query'] = $base['query']; - } - } - } - if ($relative['fragment'] !== '') - { - $target['fragment'] = $relative['fragment']; - } - } - else - { - // No base URL, just return the relative URL - $target = $relative; - } - $return = SimplePie_Misc::compress_parse_url($target['scheme'], $target['authority'], $target['path'], $target['query'], $target['fragment']); + return $this->label; } else { - $return = $base; + return null; } - $return = SimplePie_Misc::normalize_url($return); - return $return; } +} - function remove_dot_segments($input) +class SimplePie_Rating +{ + var $scheme; + var $value; + + // Constructor, used to input the data + function SimplePie_Rating($scheme = null, $value = null) { - $output = ''; - while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input == '.' || $input == '..') - { - // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise, - if (strpos($input, '../') === 0) - { - $input = substr($input, 3); - } - elseif (strpos($input, './') === 0) - { - $input = substr($input, 2); - } - // 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, - elseif (strpos($input, '/./') === 0) - { - $input = substr_replace($input, '/', 0, 3); - } - elseif ($input == '/.') - { - $input = '/'; - } - // 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, - elseif (strpos($input, '/../') === 0) - { - $input = substr_replace($input, '/', 0, 4); - $output = substr_replace($output, '', strrpos($output, '/')); - } - elseif ($input == '/..') - { - $input = '/'; - $output = substr_replace($output, '', strrpos($output, '/')); - } - // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise, - elseif ($input == '.' || $input == '..') - { - $input = ''; - } - // 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 - elseif (($pos = strpos($input, '/', 1)) !== false) - { - $output .= substr($input, 0, $pos); - $input = substr_replace($input, '', 0, $pos); - } - else - { - $output .= $input; - $input = ''; - } - } - return $output . $input; + $this->scheme = $scheme; + $this->value = $value; } - function get_element($realname, $string) + function __toString() { - $return = array(); - $name = preg_quote($realname, '/'); - if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) - { - for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++) - { - $return[$i]['tag'] = $realname; - $return[$i]['full'] = $matches[$i][0][0]; - $return[$i]['offset'] = $matches[$i][0][1]; - if (strlen($matches[$i][3][0]) <= 2) - { - $return[$i]['self_closing'] = true; - } - else - { - $return[$i]['self_closing'] = false; - $return[$i]['content'] = $matches[$i][4][0]; - } - $return[$i]['attribs'] = array(); - if (isset($matches[$i][2][0]) && preg_match_all('/((?:[^\s:]+:)?[^\s:]+)(?:\s*=\s*(?:"([^"]*)"|\'([^\']*)\'|([a-z0-9\-._:]*)))?\s/U', ' ' . $matches[$i][2][0] . ' ', $attribs, PREG_SET_ORDER)) - { - for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++) - { - if (count($attribs[$j]) == 2) - { - $attribs[$j][2] = $attribs[$j][1]; - } - $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8'); - } - } - } - } - return $return; + // There is no $this->data here + return md5(serialize($this)); } - function element_implode($element) + function get_scheme() { - $full = "<$element[tag]"; - foreach ($element['attribs'] as $key => $value) - { - $key = strtolower($key); - $full .= " $key=\"" . htmlspecialchars($value['data']) . '"'; - } - if ($element['self_closing']) + if ($this->scheme !== null) { - $full .= ' />'; + return $this->scheme; } else { - $full .= ">$element[content]"; + return null; } - return $full; } - function error($message, $level, $file, $line) + function get_value() { - switch ($level) + if ($this->value !== null) { - case E_USER_ERROR: - $note = 'PHP Error'; - break; - case E_USER_WARNING: - $note = 'PHP Warning'; - break; - case E_USER_NOTICE: - $note = 'PHP Notice'; - break; - default: - $note = 'Unknown Error'; - break; - } - error_log("$note: $message in $file on line $line", 0); - return $message; - } - - /** - * If a file has been cached, retrieve and display it. - * - * This is most useful for caching images (get_favicon(), etc.), - * however it works for all cached files. This WILL NOT display ANY - * file/image/page/whatever, but rather only display what has already - * been cached by SimplePie. - * - * @access public - * @see SimplePie::get_favicon() - * @param str $identifier_url URL that is used to identify the content. - * This may or may not be the actual URL of the live content. - * @param str $cache_location Location of SimplePie's cache. Defaults - * to './cache'. - * @param str $cache_extension The file extension that the file was - * cached with. Defaults to 'spc'. - * @param str $cache_class Name of the cache-handling class being used - * in SimplePie. Defaults to 'SimplePie_Cache', and should be left - * as-is unless you've overloaded the class. - * @param str $cache_name_function Function that converts the filename - * for saving. Defaults to 'md5'. - */ - function display_cached_file($identifier_url, $cache_location = './cache', $cache_extension = 'spc', $cache_class = 'SimplePie_Cache', $cache_name_function = 'md5') - { - $cache = new $cache_class($cache_location, call_user_func($cache_name_function, $identifier_url), $cache_extension); - - if ($file = $cache->load()) - { - header('Content-type:' . $file['headers']['content-type']); - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days - echo $file['body']; - exit; - } - - die('Cached file for ' . $identifier_url . ' cannot be found.'); - } - - function fix_protocol($url, $http = 1) - { - $url = SimplePie_Misc::normalize_url($url); - $parsed = SimplePie_Misc::parse_url($url); - if ($parsed['scheme'] !== '' && $parsed['scheme'] != 'http' && $parsed['scheme'] != 'https') - { - return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http); - } - - if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url)) - { - return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http); - } - - if ($http == 2 && $parsed['scheme'] !== '') - { - return "feed:$url"; - } - elseif ($http == 3 && strtolower($parsed['scheme']) == 'http') - { - return substr_replace($url, 'podcast', 0, 4); - } - elseif ($http == 4 && strtolower($parsed['scheme']) == 'http') - { - return substr_replace($url, 'itpc', 0, 4); + return $this->value; } else { - return $url; + return null; } } +} - function parse_url($url) - { - static $cache = array(); - if (isset($cache[$url])) - { - return $cache[$url]; - } - elseif (preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/', $url, $match)) - { - for ($i = count($match); $i <= 9; $i++) - { - $match[$i] = ''; - } - return $cache[$url] = array('scheme' => $match[2], 'authority' => $match[4], 'path' => $match[5], 'query' => $match[7], 'fragment' => $match[9]); - } - else - { - return $cache[$url] = array('scheme' => '', 'authority' => '', 'path' => '', 'query' => '', 'fragment' => ''); - } - } +class SimplePie_Restriction +{ + var $relationship; + var $type; + var $value; - function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '') + // Constructor, used to input the data + function SimplePie_Restriction($relationship = null, $type = null, $value = null) { - $return = ''; - if ($scheme !== '') - { - $return .= "$scheme:"; - } - if ($authority !== '') - { - $return .= "//$authority"; - } - if ($path !== '') - { - $return .= $path; - } - if ($query !== '') - { - $return .= "?$query"; - } - if ($fragment !== '') - { - $return .= "#$fragment"; - } - return $return; + $this->relationship = $relationship; + $this->type = $type; + $this->value = $value; } - function normalize_url($url) + function __toString() { - $url = preg_replace_callback('/%([0-9A-Fa-f]{2})/', array('SimplePie_Misc', 'percent_encoding_normalization'), $url); - $url = SimplePie_Misc::parse_url($url); - $url['scheme'] = strtolower($url['scheme']); - if ($url['authority'] !== '') - { - $url['authority'] = strtolower($url['authority']); - $url['path'] = SimplePie_Misc::remove_dot_segments($url['path']); - } - return SimplePie_Misc::compress_parse_url($url['scheme'], $url['authority'], $url['path'], $url['query'], $url['fragment']); + // There is no $this->data here + return md5(serialize($this)); } - function percent_encoding_normalization($match) + function get_relationship() { - $integer = hexdec($match[1]); - if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer == 0x2D || $integer == 0x2E || $integer == 0x5F || $integer == 0x7E) + if ($this->relationship !== null) { - return chr($integer); + return $this->relationship; } else { - return strtoupper($match[0]); + return null; } } - /** - * Remove bad UTF-8 bytes - * - * PCRE Pattern to locate bad bytes in a UTF-8 string comes from W3C - * FAQ: Multilingual Forms (modified to include full ASCII range) - * - * @author Geoffrey Sneddon - * @see http://www.w3.org/International/questions/qa-forms-utf-8 - * @param string $str String to remove bad UTF-8 bytes from - * @return string UTF-8 string - */ - function utf8_bad_replace($str) + function get_type() { - if (function_exists('iconv')) - { - $out = iconv('UTF-8', 'UTF-8//IGNORE', $str); - if($out !== false) return $out; - } - if (function_exists('mb_convert_encoding')) - { - return mb_convert_encoding($str, 'UTF-8', 'UTF-8'); - } - 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)) - { - return implode("\xEF\xBF\xBD", $matches[0]); - } - elseif ($str !== '') + if ($this->type !== null) { - return "\xEF\xBF\xBD"; + return $this->type; } else { - return ''; + return null; } } - function change_encoding($data, $input, $output) + function get_value() { - $input = SimplePie_Misc::encoding($input); - $output = SimplePie_Misc::encoding($output); - - if (function_exists('iconv') && ($return = @iconv($input, "$output//IGNORE", $data))) - { - return $return; - } - elseif (function_exists('iconv') && ($return = @iconv($input, $output, $data))) - { - return $return; - } - elseif (function_exists('mb_convert_encoding') && ($return = @mb_convert_encoding($data, $output, $input))) - { - return $return; - } - elseif ($input == 'ISO-8859-1' && $output == 'UTF-8') + if ($this->value !== null) { - return utf8_encode($data); + return $this->value; } - elseif ($input == 'UTF-8' && $output == 'ISO-8859-1') + else { - return utf8_decode($data); + return null; } - return $data; } +} + +/** + * @todo Move to properly supporting RFC2616 (HTTP/1.1) + */ +class SimplePie_File +{ + var $url; + var $useragent; + var $success = true; + var $headers = array(); + var $body; + var $status_code; + var $redirects = 0; + var $error; + var $method = SIMPLEPIE_FILE_SOURCE_NONE; - function encoding($encoding) + function SimplePie_File($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) { - // Character sets are case-insensitive (though we'll return them in the form given in their registration) - switch (strtoupper($encoding)) + if (class_exists('idna_convert')) { - case 'ANSI_X3.4-1968': - case 'ISO-IR-6': - case 'ANSI_X3.4-1986': - case 'ISO_646.IRV:1991': - case 'ASCII': - case 'ISO646-US': - case 'US-ASCII': - case 'US': - case 'IBM367': - case 'CP367': - case 'CSASCII': - return 'US-ASCII'; - - case 'ISO_8859-1:1987': - case 'ISO-IR-100': - case 'ISO_8859-1': - case 'ISO-8859-1': - case 'LATIN1': - case 'L1': - case 'IBM819': - case 'CP819': - case 'CSISOLATIN1': - return 'ISO-8859-1'; - - case 'ISO_8859-2:1987': - case 'ISO-IR-101': - case 'ISO_8859-2': - case 'ISO-8859-2': - case 'LATIN2': - case 'L2': - case 'CSISOLATIN2': - return 'ISO-8859-2'; - - case 'ISO_8859-3:1988': - case 'ISO-IR-109': - case 'ISO_8859-3': - case 'ISO-8859-3': - case 'LATIN3': - case 'L3': - case 'CSISOLATIN3': - return 'ISO-8859-3'; - - case 'ISO_8859-4:1988': - case 'ISO-IR-110': - case 'ISO_8859-4': - case 'ISO-8859-4': - case 'LATIN4': - case 'L4': - case 'CSISOLATIN4': - return 'ISO-8859-4'; - - case 'ISO_8859-5:1988': - case 'ISO-IR-144': - case 'ISO_8859-5': - case 'ISO-8859-5': - case 'CYRILLIC': - case 'CSISOLATINCYRILLIC': - return 'ISO-8859-5'; - - case 'ISO_8859-6:1987': - case 'ISO-IR-127': - case 'ISO_8859-6': - case 'ISO-8859-6': - case 'ECMA-114': - case 'ASMO-708': - case 'ARABIC': - case 'CSISOLATINARABIC': - return 'ISO-8859-6'; - - case 'ISO_8859-7:1987': - case 'ISO-IR-126': - case 'ISO_8859-7': - case 'ISO-8859-7': - case 'ELOT_928': - case 'ECMA-118': - case 'GREEK': - case 'GREEK8': - case 'CSISOLATINGREEK': - return 'ISO-8859-7'; - - case 'ISO_8859-8:1988': - case 'ISO-IR-138': - case 'ISO_8859-8': - case 'ISO-8859-8': - case 'HEBREW': - case 'CSISOLATINHEBREW': - return 'ISO-8859-8'; - - case 'ISO_8859-9:1989': - case 'ISO-IR-148': - case 'ISO_8859-9': - case 'ISO-8859-9': - case 'LATIN5': - case 'L5': - case 'CSISOLATIN5': - return 'ISO-8859-9'; - - case 'ISO-8859-10': - case 'ISO-IR-157': - case 'L6': - case 'ISO_8859-10:1992': - case 'CSISOLATIN6': - case 'LATIN6': - return 'ISO-8859-10'; - - case 'ISO_6937-2-ADD': - case 'ISO-IR-142': - case 'CSISOTEXTCOMM': - return 'ISO_6937-2-add'; - - case 'JIS_X0201': - case 'X0201': - case 'CSHALFWIDTHKATAKANA': - return 'JIS_X0201'; - - case 'JIS_ENCODING': - case 'CSJISENCODING': - return 'JIS_Encoding'; - - case 'SHIFT_JIS': - case 'MS_KANJI': - case 'CSSHIFTJIS': - return 'Shift_JIS'; - - case 'EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE': - case 'CSEUCPKDFMTJAPANESE': - case 'EUC-JP': - return 'EUC-JP'; - - case 'EXTENDED_UNIX_CODE_FIXED_WIDTH_FOR_JAPANESE': - case 'CSEUCFIXWIDJAPANESE': - return 'Extended_UNIX_Code_Fixed_Width_for_Japanese'; - - case 'BS_4730': - case 'ISO-IR-4': - case 'ISO646-GB': - case 'GB': - case 'UK': - case 'CSISO4UNITEDKINGDOM': - return 'BS_4730'; - - case 'SEN_850200_C': - case 'ISO-IR-11': - case 'ISO646-SE2': - case 'SE2': - case 'CSISO11SWEDISHFORNAMES': - return 'SEN_850200_C'; - - case 'IT': - case 'ISO-IR-15': - case 'ISO646-IT': - case 'CSISO15ITALIAN': - return 'IT'; - - case 'ES': - case 'ISO-IR-17': - case 'ISO646-ES': - case 'CSISO17SPANISH': - return 'ES'; - - case 'DIN_66003': - case 'ISO-IR-21': - case 'DE': - case 'ISO646-DE': - case 'CSISO21GERMAN': - return 'DIN_66003'; - - case 'NS_4551-1': - case 'ISO-IR-60': - case 'ISO646-NO': - case 'NO': - case 'CSISO60DANISHNORWEGIAN': - case 'CSISO60NORWEGIAN1': - return 'NS_4551-1'; - - case 'NF_Z_62-010': - case 'ISO-IR-69': - case 'ISO646-FR': - case 'FR': - case 'CSISO69FRENCH': - return 'NF_Z_62-010'; - - case 'ISO-10646-UTF-1': - case 'CSISO10646UTF1': - return 'ISO-10646-UTF-1'; + $idn = new idna_convert; + $parsed = SimplePie_Misc::parse_url($url); + $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']); + } + $this->url = $url; + $this->useragent = $useragent; + if (preg_match('/^http(s)?:\/\//i', $url)) + { + if ($useragent === null) + { + $useragent = ini_get('user_agent'); + $this->useragent = $useragent; + } + if (!is_array($headers)) + { + $headers = array(); + } + if (!$force_fsockopen && function_exists('curl_exec')) + { + $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL; + $fp = curl_init(); + $headers2 = array(); + foreach ($headers as $key => $value) + { + $headers2[] = "$key: $value"; + } + if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>=')) + { + curl_setopt($fp, CURLOPT_ENCODING, ''); + } + curl_setopt($fp, CURLOPT_URL, $url); + curl_setopt($fp, CURLOPT_HEADER, 1); + curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($fp, CURLOPT_TIMEOUT, $timeout); + curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout); + curl_setopt($fp, CURLOPT_REFERER, $url); + curl_setopt($fp, CURLOPT_USERAGENT, $useragent); + curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2); + if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>=')) + { + curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects); + } - case 'ISO_646.BASIC:1983': - case 'REF': - case 'CSISO646BASIC1983': - return 'ISO_646.basic:1983'; + $this->headers = curl_exec($fp); + if (curl_errno($fp) === 23 || curl_errno($fp) === 61) + { + curl_setopt($fp, CURLOPT_ENCODING, 'none'); + $this->headers = curl_exec($fp); + } + if (curl_errno($fp)) + { + $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp); + $this->success = false; + } + else + { + $info = curl_getinfo($fp); + curl_close($fp); + $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1); + $this->headers = array_pop($this->headers); + $parser = new SimplePie_HTTP_Parser($this->headers); + if ($parser->parse()) + { + $this->headers = $parser->headers; + $this->body = $parser->body; + $this->status_code = $parser->status_code; + 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) + { + $this->redirects++; + $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); + return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen); + } + } + } + } + else + { + $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN; + $url_parts = parse_url($url); + if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') + { + $url_parts['host'] = "ssl://$url_parts[host]"; + $url_parts['port'] = 443; + } + if (!isset($url_parts['port'])) + { + $url_parts['port'] = 80; + } + $fp = @fsockopen($url_parts['host'], $url_parts['port'], $errno, $errstr, $timeout); + if (!$fp) + { + $this->error = 'fsockopen error: ' . $errstr; + $this->success = false; + } + else + { + stream_set_timeout($fp, $timeout); + if (isset($url_parts['path'])) + { + if (isset($url_parts['query'])) + { + $get = "$url_parts[path]?$url_parts[query]"; + } + else + { + $get = $url_parts['path']; + } + } + else + { + $get = '/'; + } + $out = "GET $get HTTP/1.0\r\n"; + $out .= "Host: $url_parts[host]\r\n"; + $out .= "User-Agent: $useragent\r\n"; + if (extension_loaded('zlib')) + { + $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n"; + } + + if (isset($url_parts['user']) && isset($url_parts['pass'])) + { + $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n"; + } + foreach ($headers as $key => $value) + { + $out .= "$key: $value\r\n"; + } + $out .= "Connection: Close\r\n\r\n"; + fwrite($fp, $out); + + $info = stream_get_meta_data($fp); + + $this->headers = ''; + while (!$info['eof'] && !$info['timed_out']) + { + $this->headers .= fread($fp, 1160); + $info = stream_get_meta_data($fp); + } + if (!$info['timed_out']) + { + $parser = new SimplePie_HTTP_Parser($this->headers); + if ($parser->parse()) + { + $this->headers = $parser->headers; + $this->body = $parser->body; + $this->status_code = $parser->status_code; + 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) + { + $this->redirects++; + $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); + return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen); + } + if (isset($this->headers['content-encoding'])) + { + // Hey, we act dumb elsewhere, so let's do that here too + switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20"))) + { + case 'gzip': + case 'x-gzip': + $decoder = new SimplePie_gzdecode($this->body); + if (!$decoder->parse()) + { + $this->error = 'Unable to decode HTTP "gzip" stream'; + $this->success = false; + } + else + { + $this->body = $decoder->data; + } + break; + + case 'deflate': + if (($body = gzuncompress($this->body)) === false) + { + if (($body = gzinflate($this->body)) === false) + { + $this->error = 'Unable to decode HTTP "deflate" stream'; + $this->success = false; + } + } + $this->body = $body; + break; + + default: + $this->error = 'Unknown content coding'; + $this->success = false; + } + } + } + } + else + { + $this->error = 'fsocket timed out'; + $this->success = false; + } + fclose($fp); + } + } + } + else + { + $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS; + if (!$this->body = file_get_contents($url)) + { + $this->error = 'file_get_contents could not read the file'; + $this->success = false; + } + } + } +} + +/** + * HTTP Response Parser + * + * @package SimplePie + */ +class SimplePie_HTTP_Parser +{ + /** + * HTTP Version + * + * @access public + * @var float + */ + var $http_version = 0.0; + + /** + * Status code + * + * @access public + * @var int + */ + var $status_code = 0; + + /** + * Reason phrase + * + * @access public + * @var string + */ + var $reason = ''; + + /** + * Key/value pairs of the headers + * + * @access public + * @var array + */ + var $headers = array(); + + /** + * Body of the response + * + * @access public + * @var string + */ + var $body = ''; + + /** + * Current state of the state machine + * + * @access private + * @var string + */ + var $state = 'http_version'; + + /** + * Input data + * + * @access private + * @var string + */ + var $data = ''; + + /** + * Input data length (to avoid calling strlen() everytime this is needed) + * + * @access private + * @var int + */ + var $data_length = 0; + + /** + * Current position of the pointer + * + * @var int + * @access private + */ + var $position = 0; + + /** + * Name of the hedaer currently being parsed + * + * @access private + * @var string + */ + var $name = ''; + + /** + * Value of the hedaer currently being parsed + * + * @access private + * @var string + */ + var $value = ''; + + /** + * Create an instance of the class with the input data + * + * @access public + * @param string $data Input data + */ + function SimplePie_HTTP_Parser($data) + { + $this->data = $data; + $this->data_length = strlen($this->data); + } + + /** + * Parse the input data + * + * @access public + * @return bool true on success, false on failure + */ + function parse() + { + while ($this->state && $this->state !== 'emit' && $this->has_data()) + { + $state = $this->state; + $this->$state(); + } + $this->data = ''; + if ($this->state === 'emit' || $this->state === 'body') + { + return true; + } + else + { + $this->http_version = ''; + $this->status_code = ''; + $this->reason = ''; + $this->headers = array(); + $this->body = ''; + return false; + } + } + + /** + * Check whether there is data beyond the pointer + * + * @access private + * @return bool true if there is further data, false if not + */ + function has_data() + { + return (bool) ($this->position < $this->data_length); + } + + /** + * See if the next character is LWS + * + * @access private + * @return bool true if the next character is LWS, false if not + */ + function is_linear_whitespace() + { + return (bool) ($this->data[$this->position] === "\x09" + || $this->data[$this->position] === "\x20" + || ($this->data[$this->position] === "\x0A" + && isset($this->data[$this->position + 1]) + && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20"))); + } + + /** + * Parse the HTTP version + * + * @access private + */ + function http_version() + { + if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/') + { + $len = strspn($this->data, '0123456789.', 5); + $this->http_version = substr($this->data, 5, $len); + $this->position += 5 + $len; + if (substr_count($this->http_version, '.') <= 1) + { + $this->http_version = (float) $this->http_version; + $this->position += strspn($this->data, "\x09\x20", $this->position); + $this->state = 'status'; + } + else + { + $this->state = false; + } + } + else + { + $this->state = false; + } + } + + /** + * Parse the status code + * + * @access private + */ + function status() + { + if ($len = strspn($this->data, '0123456789', $this->position)) + { + $this->status_code = (int) substr($this->data, $this->position, $len); + $this->position += $len; + $this->state = 'reason'; + } + else + { + $this->state = false; + } + } + + /** + * Parse the reason phrase + * + * @access private + */ + function reason() + { + $len = strcspn($this->data, "\x0A", $this->position); + $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20"); + $this->position += $len + 1; + $this->state = 'new_line'; + } + + /** + * Deal with a new line, shifting data around as needed + * + * @access private + */ + function new_line() + { + $this->value = trim($this->value, "\x0D\x20"); + if ($this->name !== '' && $this->value !== '') + { + $this->name = strtolower($this->name); + if (isset($this->headers[$this->name])) + { + $this->headers[$this->name] .= ', ' . $this->value; + } + else + { + $this->headers[$this->name] = $this->value; + } + } + $this->name = ''; + $this->value = ''; + if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A") + { + $this->position += 2; + $this->state = 'body'; + } + elseif ($this->data[$this->position] === "\x0A") + { + $this->position++; + $this->state = 'body'; + } + else + { + $this->state = 'name'; + } + } + + /** + * Parse a header name + * + * @access private + */ + function name() + { + $len = strcspn($this->data, "\x0A:", $this->position); + if (isset($this->data[$this->position + $len])) + { + if ($this->data[$this->position + $len] === "\x0A") + { + $this->position += $len; + $this->state = 'new_line'; + } + else + { + $this->name = substr($this->data, $this->position, $len); + $this->position += $len + 1; + $this->state = 'value'; + } + } + else + { + $this->state = false; + } + } + + /** + * Parse LWS, replacing consecutive LWS characters with a single space + * + * @access private + */ + function linear_whitespace() + { + do + { + if (substr($this->data, $this->position, 2) === "\x0D\x0A") + { + $this->position += 2; + } + elseif ($this->data[$this->position] === "\x0A") + { + $this->position++; + } + $this->position += strspn($this->data, "\x09\x20", $this->position); + } while ($this->has_data() && $this->is_linear_whitespace()); + $this->value .= "\x20"; + } + + /** + * See what state to move to while within non-quoted header values + * + * @access private + */ + function value() + { + if ($this->is_linear_whitespace()) + { + $this->linear_whitespace(); + } + else + { + switch ($this->data[$this->position]) + { + case '"': + $this->position++; + $this->state = 'quote'; + break; + + case "\x0A": + $this->position++; + $this->state = 'new_line'; + break; + + default: + $this->state = 'value_char'; + break; + } + } + } + + /** + * Parse a header value while outside quotes + * + * @access private + */ + function value_char() + { + $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position); + $this->value .= substr($this->data, $this->position, $len); + $this->position += $len; + $this->state = 'value'; + } + + /** + * See what state to move to while within quoted header values + * + * @access private + */ + function quote() + { + if ($this->is_linear_whitespace()) + { + $this->linear_whitespace(); + } + else + { + switch ($this->data[$this->position]) + { + case '"': + $this->position++; + $this->state = 'value'; + break; + + case "\x0A": + $this->position++; + $this->state = 'new_line'; + break; + + case '\\': + $this->position++; + $this->state = 'quote_escaped'; + break; + + default: + $this->state = 'quote_char'; + break; + } + } + } + + /** + * Parse a header value while within quotes + * + * @access private + */ + function quote_char() + { + $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position); + $this->value .= substr($this->data, $this->position, $len); + $this->position += $len; + $this->state = 'value'; + } + + /** + * Parse an escaped character within quotes + * + * @access private + */ + function quote_escaped() + { + $this->value .= $this->data[$this->position]; + $this->position++; + $this->state = 'quote'; + } + + /** + * Parse the body + * + * @access private + */ + function body() + { + $this->body = substr($this->data, $this->position); + $this->state = 'emit'; + } +} + +/** + * gzdecode + * + * @package SimplePie + */ +class SimplePie_gzdecode +{ + /** + * Compressed data + * + * @access private + * @see gzdecode::$data + */ + var $compressed_data; + + /** + * Size of compressed data + * + * @access private + */ + var $compressed_size; + + /** + * Minimum size of a valid gzip string + * + * @access private + */ + var $min_compressed_size = 18; + + /** + * Current position of pointer + * + * @access private + */ + var $position = 0; + + /** + * Flags (FLG) + * + * @access private + */ + var $flags; + + /** + * Uncompressed data + * + * @access public + * @see gzdecode::$compressed_data + */ + var $data; + + /** + * Modified time + * + * @access public + */ + var $MTIME; + + /** + * Extra Flags + * + * @access public + */ + var $XFL; + + /** + * Operating System + * + * @access public + */ + var $OS; + + /** + * Subfield ID 1 + * + * @access public + * @see gzdecode::$extra_field + * @see gzdecode::$SI2 + */ + var $SI1; + + /** + * Subfield ID 2 + * + * @access public + * @see gzdecode::$extra_field + * @see gzdecode::$SI1 + */ + var $SI2; + + /** + * Extra field content + * + * @access public + * @see gzdecode::$SI1 + * @see gzdecode::$SI2 + */ + var $extra_field; + + /** + * Original filename + * + * @access public + */ + var $filename; + + /** + * Human readable comment + * + * @access public + */ + var $comment; + + /** + * Don't allow anything to be set + * + * @access public + */ + function __set($name, $value) + { + trigger_error("Cannot write property $name", E_USER_ERROR); + } + + /** + * Set the compressed string and related properties + * + * @access public + */ + function SimplePie_gzdecode($data) + { + $this->compressed_data = $data; + $this->compressed_size = strlen($data); + } + + /** + * Decode the GZIP stream + * + * @access public + */ + function parse() + { + if ($this->compressed_size >= $this->min_compressed_size) + { + // Check ID1, ID2, and CM + if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08") + { + return false; + } + + // Get the FLG (FLaGs) + $this->flags = ord($this->compressed_data[3]); + + // FLG bits above (1 << 4) are reserved + if ($this->flags > 0x1F) + { + return false; + } + + // Advance the pointer after the above + $this->position += 4; + + // MTIME + $mtime = substr($this->compressed_data, $this->position, 4); + // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness + if (current(unpack('S', "\x00\x01")) === 1) + { + $mtime = strrev($mtime); + } + $this->MTIME = current(unpack('l', $mtime)); + $this->position += 4; + + // Get the XFL (eXtra FLags) + $this->XFL = ord($this->compressed_data[$this->position++]); + + // Get the OS (Operating System) + $this->OS = ord($this->compressed_data[$this->position++]); + + // Parse the FEXTRA + if ($this->flags & 4) + { + // Read subfield IDs + $this->SI1 = $this->compressed_data[$this->position++]; + $this->SI2 = $this->compressed_data[$this->position++]; + + // SI2 set to zero is reserved for future use + if ($this->SI2 === "\x00") + { + return false; + } + + // Get the length of the extra field + $len = current(unpack('v', substr($this->compressed_data, $this->position, 2))); + $position += 2; + + // Check the length of the string is still valid + $this->min_compressed_size += $len + 4; + if ($this->compressed_size >= $this->min_compressed_size) + { + // Set the extra field to the given data + $this->extra_field = substr($this->compressed_data, $this->position, $len); + $this->position += $len; + } + else + { + return false; + } + } + + // Parse the FNAME + if ($this->flags & 8) + { + // Get the length of the filename + $len = strcspn($this->compressed_data, "\x00", $this->position); + + // Check the length of the string is still valid + $this->min_compressed_size += $len + 1; + if ($this->compressed_size >= $this->min_compressed_size) + { + // Set the original filename to the given string + $this->filename = substr($this->compressed_data, $this->position, $len); + $this->position += $len + 1; + } + else + { + return false; + } + } + + // Parse the FCOMMENT + if ($this->flags & 16) + { + // Get the length of the comment + $len = strcspn($this->compressed_data, "\x00", $this->position); + + // Check the length of the string is still valid + $this->min_compressed_size += $len + 1; + if ($this->compressed_size >= $this->min_compressed_size) + { + // Set the original comment to the given string + $this->comment = substr($this->compressed_data, $this->position, $len); + $this->position += $len + 1; + } + else + { + return false; + } + } + + // Parse the FHCRC + if ($this->flags & 2) + { + // Check the length of the string is still valid + $this->min_compressed_size += $len + 2; + if ($this->compressed_size >= $this->min_compressed_size) + { + // Read the CRC + $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2))); + + // Check the CRC matches + if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc) + { + $this->position += 2; + } + else + { + return false; + } + } + else + { + return false; + } + } + + // Decompress the actual data + if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false) + { + return false; + } + else + { + $this->position = $this->compressed_size - 8; + } + + // Check CRC of data + $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4))); + $this->position += 4; + /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc)) + { + return false; + }*/ + + // Check ISIZE of data + $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4))); + $this->position += 4; + if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize)) + { + return false; + } + + // Wow, against all odds, we've actually got a valid gzip string + return true; + } + else + { + return false; + } + } +} + +class SimplePie_Cache +{ + /** + * Don't call the constructor. Please. + * + * @access private + */ + function SimplePie_Cache() + { + trigger_error('Please call SimplePie_Cache::create() instead of the constructor', E_USER_ERROR); + } + + /** + * Create a new SimplePie_Cache object + * + * @static + * @access public + */ + function create($location, $filename, $extension) + { + $location_iri = new SimplePie_IRI($location); + switch ($location_iri->get_scheme()) + { + case 'mysql': + if (extension_loaded('mysql')) + { + return new SimplePie_Cache_MySQL($location_iri, $filename, $extension); + } + break; + + default: + return new SimplePie_Cache_File($location, $filename, $extension); + } + } +} + +class SimplePie_Cache_File +{ + var $location; + var $filename; + var $extension; + var $name; + + function SimplePie_Cache_File($location, $filename, $extension) + { + $this->location = $location; + $this->filename = $filename; + $this->extension = $extension; + $this->name = "$this->location/$this->filename.$this->extension"; + } + + function save($data) + { + if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location)) + { + if (is_a($data, 'SimplePie')) + { + $data = $data->data; + } + + $data = serialize($data); + + if (function_exists('file_put_contents')) + { + return (bool) file_put_contents($this->name, $data); + } + else + { + $fp = fopen($this->name, 'wb'); + if ($fp) + { + fwrite($fp, $data); + fclose($fp); + return true; + } + } + } + return false; + } + + function load() + { + if (file_exists($this->name) && is_readable($this->name)) + { + return unserialize(file_get_contents($this->name)); + } + return false; + } + + function mtime() + { + if (file_exists($this->name)) + { + return filemtime($this->name); + } + return false; + } + + function touch() + { + if (file_exists($this->name)) + { + return touch($this->name); + } + return false; + } + + function unlink() + { + if (file_exists($this->name)) + { + return unlink($this->name); + } + return false; + } +} + +class SimplePie_Cache_DB +{ + function prepare_simplepie_object_for_cache($data) + { + $items = $data->get_items(); + $items_by_id = array(); + + if (!empty($items)) + { + foreach ($items as $item) + { + $items_by_id[$item->get_id()] = $item; + } + + if (count($items_by_id) !== count($items)) + { + $items_by_id = array(); + foreach ($items as $item) + { + $items_by_id[$item->get_id(true)] = $item; + } + } + + if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0])) + { + $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]; + } + elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0])) + { + $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]; + } + elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0])) + { + $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]; + } + elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0])) + { + $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]; + } + else + { + $channel = null; + } + + if ($channel !== null) + { + if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'])) + { + unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']); + } + if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry'])) + { + unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']); + } + if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])) + { + unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']); + } + if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])) + { + unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']); + } + if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item'])) + { + unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']); + } + } + if (isset($data->data['items'])) + { + unset($data->data['items']); + } + if (isset($data->data['ordered_items'])) + { + unset($data->data['ordered_items']); + } + } + return array(serialize($data->data), $items_by_id); + } +} + +class SimplePie_Cache_MySQL extends SimplePie_Cache_DB +{ + var $mysql; + var $options; + var $id; + + function SimplePie_Cache_MySQL($mysql_location, $name, $extension) + { + $host = $mysql_location->get_host(); + if (SimplePie_Misc::stripos($host, 'unix(') === 0 && substr($host, -1) === ')') + { + $server = ':' . substr($host, 5, -1); + } + else + { + $server = $host; + if ($mysql_location->get_port() !== null) + { + $server .= ':' . $mysql_location->get_port(); + } + } + + if (strpos($mysql_location->get_userinfo(), ':') !== false) + { + list($username, $password) = explode(':', $mysql_location->get_userinfo(), 2); + } + else + { + $username = $mysql_location->get_userinfo(); + $password = null; + } + + if ($this->mysql = mysql_connect($server, $username, $password)) + { + $this->id = $name . $extension; + $this->options = SimplePie_Misc::parse_str($mysql_location->get_query()); + if (!isset($this->options['prefix'][0])) + { + $this->options['prefix'][0] = ''; + } + + if (mysql_select_db(ltrim($mysql_location->get_path(), '/')) + && mysql_query('SET NAMES utf8') + && ($query = mysql_unbuffered_query('SHOW TABLES'))) + { + $db = array(); + while ($row = mysql_fetch_row($query)) + { + $db[] = $row[0]; + } + + if (!in_array($this->options['prefix'][0] . 'cache_data', $db)) + { + 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)))')) + { + $this->mysql = null; + } + } + + if (!in_array($this->options['prefix'][0] . 'items', $db)) + { + 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)))')) + { + $this->mysql = null; + } + } + } + else + { + $this->mysql = null; + } + } + } + + function save($data) + { + if ($this->mysql) + { + $feed_id = "'" . mysql_real_escape_string($this->id) . "'"; + + if (is_a($data, 'SimplePie')) + { + if (SIMPLEPIE_PHP5) + { + // This keyword needs to defy coding standards for PHP4 compatibility + $data = clone($data); + } + + $prepared = $this->prepare_simplepie_object_for_cache($data); + + if ($query = mysql_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = ' . $feed_id, $this->mysql)) + { + if (mysql_num_rows($query)) + { + $items = count($prepared[1]); + if ($items) + { + $sql = 'UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `items` = ' . $items . ', `data` = \'' . mysql_real_escape_string($prepared[0]) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id; + } + else + { + $sql = 'UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `data` = \'' . mysql_real_escape_string($prepared[0]) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id; + } + + if (!mysql_query($sql, $this->mysql)) + { + return false; + } + } + 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)) + { + return false; + } + + $ids = array_keys($prepared[1]); + if (!empty($ids)) + { + foreach ($ids as $id) + { + $database_ids[] = mysql_real_escape_string($id); + } + + 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)) + { + $existing_ids = array(); + while ($row = mysql_fetch_row($query)) + { + $existing_ids[] = $row[0]; + } + + $new_ids = array_diff($ids, $existing_ids); + + foreach ($new_ids as $new_id) + { + if (!($date = $prepared[1][$new_id]->get_date('U'))) + { + $date = time(); + } + + 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)) + { + return false; + } + } + return true; + } + } + else + { + return true; + } + } + } + elseif ($query = mysql_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = ' . $feed_id, $this->mysql)) + { + if (mysql_num_rows($query)) + { + 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)) + { + return true; + } + } + 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)) + { + return true; + } + } + } + return false; + } + + function load() + { + 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))) + { + $data = unserialize($row[1]); + + if (isset($this->options['items'][0])) + { + $items = (int) $this->options['items'][0]; + } + else + { + $items = (int) $row[0]; + } + + if ($items !== 0) + { + if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0])) + { + $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]; + } + elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0])) + { + $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]; + } + elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0])) + { + $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]; + } + elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0])) + { + $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]; + } + else + { + $feed = null; + } + + if ($feed !== null) + { + $sql = 'SELECT `data` FROM `' . $this->options['prefix'][0] . 'items` WHERE `feed_id` = \'' . mysql_real_escape_string($this->id) . '\' ORDER BY `posted` DESC'; + if ($items > 0) + { + $sql .= ' LIMIT ' . $items; + } + + if ($query = mysql_unbuffered_query($sql, $this->mysql)) + { + while ($row = mysql_fetch_row($query)) + { + $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row[0]); + } + } + else + { + return false; + } + } + } + return $data; + } + return false; + } + + function mtime() + { + 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))) + { + return $row[0]; + } + else + { + return false; + } + } + + function touch() + { + 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)) + { + return true; + } + else + { + return false; + } + } + + function unlink() + { + 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))) + { + return true; + } + else + { + return false; + } + } +} + +class SimplePie_Misc +{ + function time_hms($seconds) + { + $time = ''; + + $hours = floor($seconds / 3600); + $remainder = $seconds % 3600; + if ($hours > 0) + { + $time .= $hours.':'; + } + + $minutes = floor($remainder / 60); + $seconds = $remainder % 60; + if ($minutes < 10 && $hours > 0) + { + $minutes = '0' . $minutes; + } + if ($seconds < 10) + { + $seconds = '0' . $seconds; + } + + $time .= $minutes.':'; + $time .= $seconds; + + return $time; + } + + function absolutize_url($relative, $base) + { + $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative); + return $iri->get_iri(); + } + + function remove_dot_segments($input) + { + $output = ''; + while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') + { + // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise, + if (strpos($input, '../') === 0) + { + $input = substr($input, 3); + } + elseif (strpos($input, './') === 0) + { + $input = substr($input, 2); + } + // 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, + elseif (strpos($input, '/./') === 0) + { + $input = substr_replace($input, '/', 0, 3); + } + elseif ($input === '/.') + { + $input = '/'; + } + // 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, + elseif (strpos($input, '/../') === 0) + { + $input = substr_replace($input, '/', 0, 4); + $output = substr_replace($output, '', strrpos($output, '/')); + } + elseif ($input === '/..') + { + $input = '/'; + $output = substr_replace($output, '', strrpos($output, '/')); + } + // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise, + elseif ($input === '.' || $input === '..') + { + $input = ''; + } + // 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 + elseif (($pos = strpos($input, '/', 1)) !== false) + { + $output .= substr($input, 0, $pos); + $input = substr_replace($input, '', 0, $pos); + } + else + { + $output .= $input; + $input = ''; + } + } + return $output . $input; + } + + function get_element($realname, $string) + { + $return = array(); + $name = preg_quote($realname, '/'); + if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) + { + for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++) + { + $return[$i]['tag'] = $realname; + $return[$i]['full'] = $matches[$i][0][0]; + $return[$i]['offset'] = $matches[$i][0][1]; + if (strlen($matches[$i][3][0]) <= 2) + { + $return[$i]['self_closing'] = true; + } + else + { + $return[$i]['self_closing'] = false; + $return[$i]['content'] = $matches[$i][4][0]; + } + $return[$i]['attribs'] = array(); + 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)) + { + for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++) + { + if (count($attribs[$j]) === 2) + { + $attribs[$j][2] = $attribs[$j][1]; + } + $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8'); + } + } + } + } + return $return; + } + + function element_implode($element) + { + $full = "<$element[tag]"; + foreach ($element['attribs'] as $key => $value) + { + $key = strtolower($key); + $full .= " $key=\"" . htmlspecialchars($value['data']) . '"'; + } + if ($element['self_closing']) + { + $full .= ' />'; + } + else + { + $full .= ">$element[content]"; + } + return $full; + } + + function error($message, $level, $file, $line) + { + if ((ini_get('error_reporting') & $level) > 0) + { + switch ($level) + { + case E_USER_ERROR: + $note = 'PHP Error'; + break; + case E_USER_WARNING: + $note = 'PHP Warning'; + break; + case E_USER_NOTICE: + $note = 'PHP Notice'; + break; + default: + $note = 'Unknown Error'; + break; + } + + $log_error = true; + if (!function_exists('error_log')) + { + $log_error = false; + } + + $log_file = @ini_get('error_log'); + if (!empty($log_file) && ('syslog' != $log_file) && !@is_writable($log_file)) + { + $log_error = false; + } + + if ($log_error) + { + @error_log("$note: $message in $file on line $line", 0); + } + } + + return $message; + } + + /** + * If a file has been cached, retrieve and display it. + * + * This is most useful for caching images (get_favicon(), etc.), + * however it works for all cached files. This WILL NOT display ANY + * file/image/page/whatever, but rather only display what has already + * been cached by SimplePie. + * + * @access public + * @see SimplePie::get_favicon() + * @param str $identifier_url URL that is used to identify the content. + * This may or may not be the actual URL of the live content. + * @param str $cache_location Location of SimplePie's cache. Defaults + * to './cache'. + * @param str $cache_extension The file extension that the file was + * cached with. Defaults to 'spc'. + * @param str $cache_class Name of the cache-handling class being used + * in SimplePie. Defaults to 'SimplePie_Cache', and should be left + * as-is unless you've overloaded the class. + * @param str $cache_name_function Obsolete. Exists for backwards + * compatibility reasons only. + */ + function display_cached_file($identifier_url, $cache_location = './cache', $cache_extension = 'spc', $cache_class = 'SimplePie_Cache', $cache_name_function = 'md5') + { + $cache = call_user_func(array($cache_class, 'create'), $cache_location, $identifier_url, $cache_extension); + + if ($file = $cache->load()) + { + if (isset($file['headers']['content-type'])) + { + header('Content-type:' . $file['headers']['content-type']); + } + else + { + header('Content-type: application/octet-stream'); + } + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days + echo $file['body']; + exit; + } + + die('Cached file for ' . $identifier_url . ' cannot be found.'); + } + + function fix_protocol($url, $http = 1) + { + $url = SimplePie_Misc::normalize_url($url); + $parsed = SimplePie_Misc::parse_url($url); + if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https') + { + return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http); + } + + if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url)) + { + return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http); + } + + if ($http === 2 && $parsed['scheme'] !== '') + { + return "feed:$url"; + } + elseif ($http === 3 && strtolower($parsed['scheme']) === 'http') + { + return substr_replace($url, 'podcast', 0, 4); + } + elseif ($http === 4 && strtolower($parsed['scheme']) === 'http') + { + return substr_replace($url, 'itpc', 0, 4); + } + else + { + return $url; + } + } + + function parse_url($url) + { + $iri = new SimplePie_IRI($url); + return array( + 'scheme' => (string) $iri->get_scheme(), + 'authority' => (string) $iri->get_authority(), + 'path' => (string) $iri->get_path(), + 'query' => (string) $iri->get_query(), + 'fragment' => (string) $iri->get_fragment() + ); + } + + function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '') + { + $iri = new SimplePie_IRI(''); + $iri->set_scheme($scheme); + $iri->set_authority($authority); + $iri->set_path($path); + $iri->set_query($query); + $iri->set_fragment($fragment); + return $iri->get_iri(); + } + + function normalize_url($url) + { + $iri = new SimplePie_IRI($url); + return $iri->get_iri(); + } + + function percent_encoding_normalization($match) + { + $integer = hexdec($match[1]); + if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E) + { + return chr($integer); + } + else + { + return strtoupper($match[0]); + } + } + + /** + * Remove bad UTF-8 bytes + * + * PCRE Pattern to locate bad bytes in a UTF-8 string comes from W3C + * FAQ: Multilingual Forms (modified to include full ASCII range) + * + * @author Geoffrey Sneddon + * @see http://www.w3.org/International/questions/qa-forms-utf-8 + * @param string $str String to remove bad UTF-8 bytes from + * @return string UTF-8 string + */ + function utf8_bad_replace($str) + { + if (function_exists('iconv') && ($return = @iconv('UTF-8', 'UTF-8//IGNORE', $str))) + { + return $return; + } + elseif (function_exists('mb_convert_encoding') && ($return = @mb_convert_encoding($str, 'UTF-8', 'UTF-8'))) + { + return $return; + } + 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)) + { + return implode("\xEF\xBF\xBD", $matches[0]); + } + elseif ($str !== '') + { + return "\xEF\xBF\xBD"; + } + else + { + return ''; + } + } + + /** + * Converts a Windows-1252 encoded string to a UTF-8 encoded string + * + * @static + * @access public + * @param string $string Windows-1252 encoded string + * @return string UTF-8 encoded string + */ + function windows_1252_to_utf8($string) + { + 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"); + + return strtr($string, $convert_table); + } + + function change_encoding($data, $input, $output) + { + $input = SimplePie_Misc::encoding($input); + $output = SimplePie_Misc::encoding($output); + + // We fail to fail on non US-ASCII bytes + if ($input === 'US-ASCII') + { + static $non_ascii_octects = ''; + if (!$non_ascii_octects) + { + for ($i = 0x80; $i <= 0xFF; $i++) + { + $non_ascii_octects .= chr($i); + } + } + $data = substr($data, 0, strcspn($data, $non_ascii_octects)); + } + + // This is first, as behaviour of this is completely predictable + if ($input === 'Windows-1252' && $output === 'UTF-8') + { + return SimplePie_Misc::windows_1252_to_utf8($data); + } + // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported). + elseif (function_exists('mb_convert_encoding') && @mb_convert_encoding("\x80", 'UTF-16BE', $input) !== "\x00\x80" && ($return = @mb_convert_encoding($data, $output, $input))) + { + return $return; + } + // This is last, as behaviour of this varies with OS userland and PHP version + elseif (function_exists('iconv') && ($return = @iconv($input, $output, $data))) + { + return $return; + } + // If we can't do anything, just fail + else + { + return false; + } + } + + function encoding($charset) + { + // Normalization from UTS #22 + switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset))) + { + case 'adobestandardencoding': + case 'csadobestandardencoding': + return 'Adobe-Standard-Encoding'; + + case 'adobesymbolencoding': + case 'cshppsmath': + return 'Adobe-Symbol-Encoding'; + + case 'ami1251': + case 'amiga1251': + return 'Amiga-1251'; + + case 'ansix31101983': + case 'csat5001983': + case 'csiso99naplps': + case 'isoir99': + case 'naplps': + return 'ANSI_X3.110-1983'; + + case 'arabic7': + case 'asmo449': + case 'csiso89asmo449': + case 'iso9036': + case 'isoir89': + return 'ASMO_449'; + + case 'big5': + case 'csbig5': + case 'xxbig5': + return 'Big5'; + + case 'big5hkscs': + return 'Big5-HKSCS'; + + case 'bocu1': + case 'csbocu1': + return 'BOCU-1'; + + case 'brf': + case 'csbrf': + return 'BRF'; + + case 'bs4730': + case 'csiso4unitedkingdom': + case 'gb': + case 'iso646gb': + case 'isoir4': + case 'uk': + return 'BS_4730'; + + case 'bsviewdata': + case 'csiso47bsviewdata': + case 'isoir47': + return 'BS_viewdata'; + + case 'cesu8': + case 'cscesu8': + return 'CESU-8'; + + case 'ca': + case 'csa71': + case 'csaz243419851': + case 'csiso121canadian1': + case 'iso646ca': + case 'isoir121': + return 'CSA_Z243.4-1985-1'; + + case 'csa72': + case 'csaz243419852': + case 'csiso122canadian2': + case 'iso646ca2': + case 'isoir122': + return 'CSA_Z243.4-1985-2'; + + case 'csaz24341985gr': + case 'csiso123csaz24341985gr': + case 'isoir123': + return 'CSA_Z243.4-1985-gr'; + + case 'csiso139csn369103': + case 'csn369103': + case 'isoir139': + return 'CSN_369103'; + + case 'csdecmcs': + case 'dec': + case 'decmcs': + return 'DEC-MCS'; + + case 'csiso21german': + case 'de': + case 'din66003': + case 'iso646de': + case 'isoir21': + return 'DIN_66003'; + + case 'csdkus': + case 'dkus': + return 'dk-us'; + + case 'csiso646danish': + case 'dk': + case 'ds2089': + case 'iso646dk': + return 'DS_2089'; + + case 'csibmebcdicatde': + case 'ebcdicatde': + return 'EBCDIC-AT-DE'; + + case 'csebcdicatdea': + case 'ebcdicatdea': + return 'EBCDIC-AT-DE-A'; + + case 'csebcdiccafr': + case 'ebcdiccafr': + return 'EBCDIC-CA-FR'; + + case 'csebcdicdkno': + case 'ebcdicdkno': + return 'EBCDIC-DK-NO'; + + case 'csebcdicdknoa': + case 'ebcdicdknoa': + return 'EBCDIC-DK-NO-A'; + + case 'csebcdices': + case 'ebcdices': + return 'EBCDIC-ES'; + + case 'csebcdicesa': + case 'ebcdicesa': + return 'EBCDIC-ES-A'; + + case 'csebcdicess': + case 'ebcdicess': + return 'EBCDIC-ES-S'; + + case 'csebcdicfise': + case 'ebcdicfise': + return 'EBCDIC-FI-SE'; + + case 'csebcdicfisea': + case 'ebcdicfisea': + return 'EBCDIC-FI-SE-A'; + + case 'csebcdicfr': + case 'ebcdicfr': + return 'EBCDIC-FR'; + + case 'csebcdicit': + case 'ebcdicit': + return 'EBCDIC-IT'; + + case 'csebcdicpt': + case 'ebcdicpt': + return 'EBCDIC-PT'; + + case 'csebcdicuk': + case 'ebcdicuk': + return 'EBCDIC-UK'; + + case 'csebcdicus': + case 'ebcdicus': + return 'EBCDIC-US'; + + case 'csiso111ecmacyrillic': + case 'ecmacyrillic': + case 'isoir111': + case 'koi8e': + return 'ECMA-cyrillic'; + + case 'csiso17spanish': + case 'es': + case 'iso646es': + case 'isoir17': + return 'ES'; + + case 'csiso85spanish2': + case 'es2': + case 'iso646es2': + case 'isoir85': + return 'ES2'; + + case 'cseucfixwidjapanese': + case 'extendedunixcodefixedwidthforjapanese': + return 'Extended_UNIX_Code_Fixed_Width_for_Japanese'; + + case 'cseucpkdfmtjapanese': + case 'eucjp': + case 'extendedunixcodepackedformatforjapanese': + return 'Extended_UNIX_Code_Packed_Format_for_Japanese'; + + case 'gb18030': + return 'GB18030'; + + case 'chinese': + case 'cp936': + case 'csgb2312': + case 'csiso58gb231280': + case 'gb2312': + case 'gb231280': + case 'gbk': + case 'isoir58': + case 'ms936': + case 'windows936': + return 'GBK'; + + case 'cn': + case 'csiso57gb1988': + case 'gb198880': + case 'iso646cn': + case 'isoir57': + return 'GB_1988-80'; + + case 'csiso153gost1976874': + case 'gost1976874': + case 'isoir153': + case 'stsev35888': + return 'GOST_19768-74'; + + case 'csiso150': + case 'csiso150greekccitt': + case 'greekccitt': + case 'isoir150': + return 'greek-ccitt'; + + case 'csiso88greek7': + case 'greek7': + case 'isoir88': + return 'greek7'; + + case 'csiso18greek7old': + case 'greek7old': + case 'isoir18': + return 'greek7-old'; + + case 'cshpdesktop': + case 'hpdesktop': + return 'HP-DeskTop'; + + case 'cshplegal': + case 'hplegal': + return 'HP-Legal'; + + case 'cshpmath8': + case 'hpmath8': + return 'HP-Math8'; + + case 'cshppifont': + case 'hppifont': + return 'HP-Pi-font'; + + case 'cshproman8': + case 'hproman8': + case 'r8': + case 'roman8': + return 'hp-roman8'; + + case 'hzgb2312': + return 'HZ-GB-2312'; + + case 'csibmsymbols': + case 'ibmsymbols': + return 'IBM-Symbols'; + + case 'csibmthai': + case 'ibmthai': + return 'IBM-Thai'; + + case 'ccsid858': + case 'cp858': + case 'ibm858': + case 'pcmultilingual850euro': + return 'IBM00858'; + + case 'ccsid924': + case 'cp924': + case 'ebcdiclatin9euro': + case 'ibm924': + return 'IBM00924'; + + case 'ccsid1140': + case 'cp1140': + case 'ebcdicus37euro': + case 'ibm1140': + return 'IBM01140'; + + case 'ccsid1141': + case 'cp1141': + case 'ebcdicde273euro': + case 'ibm1141': + return 'IBM01141'; + + case 'ccsid1142': + case 'cp1142': + case 'ebcdicdk277euro': + case 'ebcdicno277euro': + case 'ibm1142': + return 'IBM01142'; + + case 'ccsid1143': + case 'cp1143': + case 'ebcdicfi278euro': + case 'ebcdicse278euro': + case 'ibm1143': + return 'IBM01143'; + + case 'ccsid1144': + case 'cp1144': + case 'ebcdicit280euro': + case 'ibm1144': + return 'IBM01144'; + + case 'ccsid1145': + case 'cp1145': + case 'ebcdices284euro': + case 'ibm1145': + return 'IBM01145'; + + case 'ccsid1146': + case 'cp1146': + case 'ebcdicgb285euro': + case 'ibm1146': + return 'IBM01146'; + + case 'ccsid1147': + case 'cp1147': + case 'ebcdicfr297euro': + case 'ibm1147': + return 'IBM01147'; + + case 'ccsid1148': + case 'cp1148': + case 'ebcdicinternational500euro': + case 'ibm1148': + return 'IBM01148'; - case 'INVARIANT': - case 'CSINVARIANT': - return 'INVARIANT'; + case 'ccsid1149': + case 'cp1149': + case 'ebcdicis871euro': + case 'ibm1149': + return 'IBM01149'; - case 'ISO_646.IRV:1983': - case 'ISO-IR-2': - case 'IRV': - case 'CSISO2INTLREFVERSION': - return 'ISO_646.irv:1983'; + case 'cp37': + case 'csibm37': + case 'ebcdiccpca': + case 'ebcdiccpnl': + case 'ebcdiccpus': + case 'ebcdiccpwt': + case 'ibm37': + return 'IBM037'; - case 'NATS-SEFI': - case 'ISO-IR-8-1': - case 'CSNATSSEFI': - return 'NATS-SEFI'; + case 'cp38': + case 'csibm38': + case 'ebcdicint': + case 'ibm38': + return 'IBM038'; - case 'NATS-SEFI-ADD': - case 'ISO-IR-8-2': - case 'CSNATSSEFIADD': - return 'NATS-SEFI-ADD'; + case 'cp273': + case 'csibm273': + case 'ibm273': + return 'IBM273'; - case 'NATS-DANO': - case 'ISO-IR-9-1': - case 'CSNATSDANO': - return 'NATS-DANO'; + case 'cp274': + case 'csibm274': + case 'ebcdicbe': + case 'ibm274': + return 'IBM274'; - case 'NATS-DANO-ADD': - case 'ISO-IR-9-2': - case 'CSNATSDANOADD': - return 'NATS-DANO-ADD'; + case 'cp275': + case 'csibm275': + case 'ebcdicbr': + case 'ibm275': + return 'IBM275'; - case 'SEN_850200_B': - case 'ISO-IR-10': - case 'FI': - case 'ISO646-FI': - case 'ISO646-SE': - case 'SE': - case 'CSISO10SWEDISH': - return 'SEN_850200_B'; + case 'csibm277': + case 'ebcdiccpdk': + case 'ebcdiccpno': + case 'ibm277': + return 'IBM277'; - case 'KS_C_5601-1987': - case 'ISO-IR-149': - case 'KS_C_5601-1989': - case 'KSC_5601': - case 'KOREAN': - case 'CSKSC56011987': - return 'KS_C_5601-1987'; + case 'cp278': + case 'csibm278': + case 'ebcdiccpfi': + case 'ebcdiccpse': + case 'ibm278': + return 'IBM278'; - case 'ISO-2022-KR': - case 'CSISO2022KR': - return 'ISO-2022-KR'; + case 'cp280': + case 'csibm280': + case 'ebcdiccpit': + case 'ibm280': + return 'IBM280'; - case 'EUC-KR': - case 'CSEUCKR': - return 'EUC-KR'; + case 'cp281': + case 'csibm281': + case 'ebcdicjpe': + case 'ibm281': + return 'IBM281'; - case 'ISO-2022-JP': - case 'CSISO2022JP': - return 'ISO-2022-JP'; + case 'cp284': + case 'csibm284': + case 'ebcdiccpes': + case 'ibm284': + return 'IBM284'; - case 'ISO-2022-JP-2': - case 'CSISO2022JP2': - return 'ISO-2022-JP-2'; + case 'cp285': + case 'csibm285': + case 'ebcdiccpgb': + case 'ibm285': + return 'IBM285'; - case 'JIS_C6220-1969-JP': - case 'JIS_C6220-1969': - case 'ISO-IR-13': - case 'KATAKANA': - case 'X0201-7': - case 'CSISO13JISC6220JP': - return 'JIS_C6220-1969-jp'; + case 'cp290': + case 'csibm290': + case 'ebcdicjpkana': + case 'ibm290': + return 'IBM290'; - case 'JIS_C6220-1969-RO': - case 'ISO-IR-14': - case 'JP': - case 'ISO646-JP': - case 'CSISO14JISC6220RO': - return 'JIS_C6220-1969-ro'; + case 'cp297': + case 'csibm297': + case 'ebcdiccpfr': + case 'ibm297': + return 'IBM297'; - case 'PT': - case 'ISO-IR-16': - case 'ISO646-PT': - case 'CSISO16PORTUGUESE': - return 'PT'; + case 'cp420': + case 'csibm420': + case 'ebcdiccpar1': + case 'ibm420': + return 'IBM420'; - case 'GREEK7-OLD': - case 'ISO-IR-18': - case 'CSISO18GREEK7OLD': - return 'greek7-old'; + case 'cp423': + case 'csibm423': + case 'ebcdiccpgr': + case 'ibm423': + return 'IBM423'; - case 'LATIN-GREEK': - case 'ISO-IR-19': - case 'CSISO19LATINGREEK': - return 'latin-greek'; + case 'cp424': + case 'csibm424': + case 'ebcdiccphe': + case 'ibm424': + return 'IBM424'; - case 'NF_Z_62-010_(1973)': - case 'ISO-IR-25': - case 'ISO646-FR1': - case 'CSISO25FRENCH': - return 'NF_Z_62-010_(1973)'; + case '437': + case 'cp437': + case 'cspc8codepage437': + case 'ibm437': + return 'IBM437'; - case 'LATIN-GREEK-1': - case 'ISO-IR-27': - case 'CSISO27LATINGREEK1': - return 'Latin-greek-1'; + case 'cp500': + case 'csibm500': + case 'ebcdiccpbe': + case 'ebcdiccpch': + case 'ibm500': + return 'IBM500'; - case 'ISO_5427': - case 'ISO-IR-37': - case 'CSISO5427CYRILLIC': - return 'ISO_5427'; + case 'cp775': + case 'cspc775baltic': + case 'ibm775': + return 'IBM775'; - case 'JIS_C6226-1978': - case 'ISO-IR-42': - case 'CSISO42JISC62261978': - return 'JIS_C6226-1978'; + case '850': + case 'cp850': + case 'cspc850multilingual': + case 'ibm850': + return 'IBM850'; - case 'BS_VIEWDATA': - case 'ISO-IR-47': - case 'CSISO47BSVIEWDATA': - return 'BS_viewdata'; + case '851': + case 'cp851': + case 'csibm851': + case 'ibm851': + return 'IBM851'; - case 'INIS': - case 'ISO-IR-49': - case 'CSISO49INIS': - return 'INIS'; + case '852': + case 'cp852': + case 'cspcp852': + case 'ibm852': + return 'IBM852'; - case 'INIS-8': - case 'ISO-IR-50': - case 'CSISO50INIS8': - return 'INIS-8'; + case '855': + case 'cp855': + case 'csibm855': + case 'ibm855': + return 'IBM855'; - case 'INIS-CYRILLIC': - case 'ISO-IR-51': - case 'CSISO51INISCYRILLIC': - return 'INIS-cyrillic'; + case '857': + case 'cp857': + case 'csibm857': + case 'ibm857': + return 'IBM857'; - case 'ISO_5427:1981': - case 'ISO-IR-54': - case 'ISO5427CYRILLIC1981': - return 'ISO_5427:1981'; + case '860': + case 'cp860': + case 'csibm860': + case 'ibm860': + return 'IBM860'; - case 'ISO_5428:1980': - case 'ISO-IR-55': - case 'CSISO5428GREEK': - return 'ISO_5428:1980'; + case '861': + case 'cp861': + case 'cpis': + case 'csibm861': + case 'ibm861': + return 'IBM861'; - case 'GB_1988-80': - case 'ISO-IR-57': - case 'CN': - case 'ISO646-CN': - case 'CSISO57GB1988': - return 'GB_1988-80'; + case '862': + case 'cp862': + case 'cspc862latinhebrew': + case 'ibm862': + return 'IBM862'; - case 'GB_2312-80': - case 'ISO-IR-58': - case 'CHINESE': - case 'CSISO58GB231280': - return 'GB_2312-80'; - - case 'NS_4551-2': - case 'ISO646-NO2': - case 'ISO-IR-61': - case 'NO2': - case 'CSISO61NORWEGIAN2': - return 'NS_4551-2'; + case '863': + case 'cp863': + case 'csibm863': + case 'ibm863': + return 'IBM863'; - case 'VIDEOTEX-SUPPL': - case 'ISO-IR-70': - case 'CSISO70VIDEOTEXSUPP1': - return 'videotex-suppl'; + case 'cp864': + case 'csibm864': + case 'ibm864': + return 'IBM864'; - case 'PT2': - case 'ISO-IR-84': - case 'ISO646-PT2': - case 'CSISO84PORTUGUESE2': - return 'PT2'; + case '865': + case 'cp865': + case 'csibm865': + case 'ibm865': + return 'IBM865'; - case 'ES2': - case 'ISO-IR-85': - case 'ISO646-ES2': - case 'CSISO85SPANISH2': - return 'ES2'; + case '866': + case 'cp866': + case 'csibm866': + case 'ibm866': + return 'IBM866'; - case 'MSZ_7795.3': - case 'ISO-IR-86': - case 'ISO646-HU': - case 'HU': - case 'CSISO86HUNGARIAN': - return 'MSZ_7795.3'; + case 'cp868': + case 'cpar': + case 'csibm868': + case 'ibm868': + return 'IBM868'; - case 'JIS_C6226-1983': - case 'ISO-IR-87': - case 'X0208': - case 'JIS_X0208-1983': - case 'CSISO87JISX0208': - return 'JIS_C6226-1983'; + case '869': + case 'cp869': + case 'cpgr': + case 'csibm869': + case 'ibm869': + return 'IBM869'; - case 'GREEK7': - case 'ISO-IR-88': - case 'CSISO88GREEK7': - return 'greek7'; + case 'cp870': + case 'csibm870': + case 'ebcdiccproece': + case 'ebcdiccpyu': + case 'ibm870': + return 'IBM870'; - case 'ASMO_449': - case 'ISO_9036': - case 'ARABIC7': - case 'ISO-IR-89': - case 'CSISO89ASMO449': - return 'ASMO_449'; + case 'cp871': + case 'csibm871': + case 'ebcdiccpis': + case 'ibm871': + return 'IBM871'; - case 'ISO-IR-90': - case 'CSISO90': - return 'iso-ir-90'; + case 'cp880': + case 'csibm880': + case 'ebcdiccyrillic': + case 'ibm880': + return 'IBM880'; - case 'JIS_C6229-1984-A': - case 'ISO-IR-91': - case 'JP-OCR-A': - case 'CSISO91JISC62291984A': - return 'JIS_C6229-1984-a'; + case 'cp891': + case 'csibm891': + case 'ibm891': + return 'IBM891'; - case 'JIS_C6229-1984-B': - case 'ISO-IR-92': - case 'ISO646-JP-OCR-B': - case 'JP-OCR-B': - case 'CSISO92JISC62991984B': - return 'JIS_C6229-1984-b'; + case 'cp903': + case 'csibm903': + case 'ibm903': + return 'IBM903'; - case 'JIS_C6229-1984-B-ADD': - case 'ISO-IR-93': - case 'JP-OCR-B-ADD': - case 'CSISO93JIS62291984BADD': - return 'JIS_C6229-1984-b-add'; + case '904': + case 'cp904': + case 'csibbm904': + case 'ibm904': + return 'IBM904'; - case 'JIS_C6229-1984-HAND': - case 'ISO-IR-94': - case 'JP-OCR-HAND': - case 'CSISO94JIS62291984HAND': - return 'JIS_C6229-1984-hand'; + case 'cp905': + case 'csibm905': + case 'ebcdiccptr': + case 'ibm905': + return 'IBM905'; - case 'JIS_C6229-1984-HAND-ADD': - case 'ISO-IR-95': - case 'JP-OCR-HAND-ADD': - case 'CSISO95JIS62291984HANDADD': - return 'JIS_C6229-1984-hand-add'; + case 'cp918': + case 'csibm918': + case 'ebcdiccpar2': + case 'ibm918': + return 'IBM918'; - case 'JIS_C6229-1984-KANA': - case 'ISO-IR-96': - case 'CSISO96JISC62291984KANA': - return 'JIS_C6229-1984-kana'; + case 'cp1026': + case 'csibm1026': + case 'ibm1026': + return 'IBM1026'; - case 'ISO_2033-1983': - case 'ISO-IR-98': - case 'E13B': - case 'CSISO2033': - return 'ISO_2033-1983'; + case 'ibm1047': + return 'IBM1047'; - case 'ANSI_X3.110-1983': - case 'ISO-IR-99': - case 'CSA_T500-1983': - case 'NAPLPS': - case 'CSISO99NAPLPS': - return 'ANSI_X3.110-1983'; + case 'csiso143iecp271': + case 'iecp271': + case 'isoir143': + return 'IEC_P27-1'; - case 'T.61-7BIT': - case 'ISO-IR-102': - case 'CSISO102T617BIT': - return 'T.61-7bit'; + case 'csiso49inis': + case 'inis': + case 'isoir49': + return 'INIS'; - case 'T.61-8BIT': - case 'T.61': - case 'ISO-IR-103': - case 'CSISO103T618BIT': - return 'T.61-8bit'; + case 'csiso50inis8': + case 'inis8': + case 'isoir50': + return 'INIS-8'; - case 'ECMA-CYRILLIC': - case 'ISO-IR-111': - case 'KOI8-E': - case 'CSISO111ECMACYRILLIC': - return 'ECMA-cyrillic'; + case 'csiso51iniscyrillic': + case 'iniscyrillic': + case 'isoir51': + return 'INIS-cyrillic'; - case 'CSA_Z243.4-1985-1': - case 'ISO-IR-121': - case 'ISO646-CA': - case 'CSA7-1': - case 'CA': - case 'CSISO121CANADIAN1': - return 'CSA_Z243.4-1985-1'; + case 'csinvariant': + case 'invariant': + return 'INVARIANT'; - case 'CSA_Z243.4-1985-2': - case 'ISO-IR-122': - case 'ISO646-CA2': - case 'CSA7-2': - case 'CSISO122CANADIAN2': - return 'CSA_Z243.4-1985-2'; + case 'iso2022cn': + return 'ISO-2022-CN'; - case 'CSA_Z243.4-1985-GR': - case 'ISO-IR-123': - case 'CSISO123CSAZ24341985GR': - return 'CSA_Z243.4-1985-gr'; + case 'iso2022cnext': + return 'ISO-2022-CN-EXT'; + + case 'csiso2022jp': + case 'iso2022jp': + return 'ISO-2022-JP'; + + case 'csiso2022jp2': + case 'iso2022jp2': + return 'ISO-2022-JP-2'; + + case 'csiso2022kr': + case 'iso2022kr': + return 'ISO-2022-KR'; + + case 'cswindows30latin1': + case 'iso88591windows30latin1': + return 'ISO-8859-1-Windows-3.0-Latin-1'; + + case 'cswindows31latin1': + case 'iso88591windows31latin1': + return 'ISO-8859-1-Windows-3.1-Latin-1'; + + case 'csisolatin2': + case 'iso88592': + case 'iso885921987': + case 'isoir101': + case 'l2': + case 'latin2': + return 'ISO-8859-2'; + + case 'cswindows31latin2': + case 'iso88592windowslatin2': + return 'ISO-8859-2-Windows-Latin-2'; + + case 'csisolatin3': + case 'iso88593': + case 'iso885931988': + case 'isoir109': + case 'l3': + case 'latin3': + return 'ISO-8859-3'; + + case 'csisolatin4': + case 'iso88594': + case 'iso885941988': + case 'isoir110': + case 'l4': + case 'latin4': + return 'ISO-8859-4'; + + case 'csisolatincyrillic': + case 'cyrillic': + case 'iso88595': + case 'iso885951988': + case 'isoir144': + return 'ISO-8859-5'; + + case 'arabic': + case 'asmo708': + case 'csisolatinarabic': + case 'ecma114': + case 'iso88596': + case 'iso885961987': + case 'isoir127': + return 'ISO-8859-6'; - case 'ISO_8859-6-E': - case 'CSISO88596E': - case 'ISO-8859-6-E': + case 'csiso88596e': + case 'iso88596e': return 'ISO-8859-6-E'; - case 'ISO_8859-6-I': - case 'CSISO88596I': - case 'ISO-8859-6-I': + case 'csiso88596i': + case 'iso88596i': return 'ISO-8859-6-I'; - case 'T.101-G2': - case 'ISO-IR-128': - case 'CSISO128T101G2': - return 'T.101-G2'; + case 'csisolatingreek': + case 'ecma118': + case 'elot928': + case 'greek': + case 'greek8': + case 'iso88597': + case 'iso885971987': + case 'isoir126': + return 'ISO-8859-7'; + + case 'csisolatinhebrew': + case 'hebrew': + case 'iso88598': + case 'iso885981988': + case 'isoir138': + return 'ISO-8859-8'; - case 'ISO_8859-8-E': - case 'CSISO88598E': - case 'ISO-8859-8-E': + case 'csiso88598e': + case 'iso88598e': return 'ISO-8859-8-E'; - case 'ISO_8859-8-I': - case 'CSISO88598I': - case 'ISO-8859-8-I': + case 'csiso88598i': + case 'iso88598i': return 'ISO-8859-8-I'; - case 'CSN_369103': - case 'ISO-IR-139': - case 'CSISO139CSN369103': - return 'CSN_369103'; + case 'cswindows31latin5': + case 'iso88599windowslatin5': + return 'ISO-8859-9-Windows-Latin-5'; - case 'JUS_I.B1.002': - case 'ISO-IR-141': - case 'ISO646-YU': - case 'JS': - case 'YU': - case 'CSISO141JUSIB1002': - return 'JUS_I.B1.002'; + case 'csisolatin6': + case 'iso885910': + case 'iso8859101992': + case 'isoir157': + case 'l6': + case 'latin6': + return 'ISO-8859-10'; - case 'IEC_P27-1': - case 'ISO-IR-143': - case 'CSISO143IECP271': - return 'IEC_P27-1'; + case 'iso885913': + return 'ISO-8859-13'; - case 'JUS_I.B1.003-SERB': - case 'ISO-IR-146': - case 'SERBIAN': - case 'CSISO146SERBIAN': - return 'JUS_I.B1.003-serb'; + case 'iso885914': + case 'iso8859141998': + case 'isoceltic': + case 'isoir199': + case 'l8': + case 'latin8': + return 'ISO-8859-14'; - case 'JUS_I.B1.003-MAC': - case 'MACEDONIAN': - case 'ISO-IR-147': - case 'CSISO147MACEDONIAN': - return 'JUS_I.B1.003-mac'; + case 'iso885915': + case 'latin9': + return 'ISO-8859-15'; - case 'GREEK-CCITT': - case 'ISO-IR-150': - case 'CSISO150': - case 'CSISO150GREEKCCITT': - return 'greek-ccitt'; + case 'iso885916': + case 'iso8859162001': + case 'isoir226': + case 'l10': + case 'latin10': + return 'ISO-8859-16'; - case 'NC_NC00-10:81': - case 'CUBA': - case 'ISO-IR-151': - case 'ISO646-CU': - case 'CSISO151CUBA': - return 'NC_NC00-10:81'; + case 'iso10646j1': + return 'ISO-10646-J-1'; + + case 'csunicode': + case 'iso10646ucs2': + return 'ISO-10646-UCS-2'; + + case 'csucs4': + case 'iso10646ucs4': + return 'ISO-10646-UCS-4'; + + case 'csunicodeascii': + case 'iso10646ucsbasic': + return 'ISO-10646-UCS-Basic'; + + case 'csunicodelatin1': + case 'iso10646': + case 'iso10646unicodelatin1': + return 'ISO-10646-Unicode-Latin1'; + + case 'csiso10646utf1': + case 'iso10646utf1': + return 'ISO-10646-UTF-1'; + + case 'csiso115481': + case 'iso115481': + case 'isotr115481': + return 'ISO-11548-1'; + + case 'csiso90': + case 'isoir90': + return 'iso-ir-90'; + + case 'csunicodeibm1261': + case 'isounicodeibm1261': + return 'ISO-Unicode-IBM-1261'; + + case 'csunicodeibm1264': + case 'isounicodeibm1264': + return 'ISO-Unicode-IBM-1264'; + + case 'csunicodeibm1265': + case 'isounicodeibm1265': + return 'ISO-Unicode-IBM-1265'; + + case 'csunicodeibm1268': + case 'isounicodeibm1268': + return 'ISO-Unicode-IBM-1268'; + + case 'csunicodeibm1276': + case 'isounicodeibm1276': + return 'ISO-Unicode-IBM-1276'; + + case 'csiso646basic1983': + case 'iso646basic1983': + case 'ref': + return 'ISO_646.basic:1983'; + + case 'csiso2intlrefversion': + case 'irv': + case 'iso646irv1983': + case 'isoir2': + return 'ISO_646.irv:1983'; + + case 'csiso2033': + case 'e13b': + case 'iso20331983': + case 'isoir98': + return 'ISO_2033-1983'; + + case 'csiso5427cyrillic': + case 'iso5427': + case 'isoir37': + return 'ISO_5427'; + + case 'iso5427cyrillic1981': + case 'iso54271981': + case 'isoir54': + return 'ISO_5427:1981'; + + case 'csiso5428greek': + case 'iso54281980': + case 'isoir55': + return 'ISO_5428:1980'; - case 'ISO_6937-2-25': - case 'ISO-IR-152': - case 'CSISO6937ADD': + case 'csiso6937add': + case 'iso6937225': + case 'isoir152': return 'ISO_6937-2-25'; - case 'GOST_19768-74': - case 'ST_SEV_358-88': - case 'ISO-IR-153': - case 'CSISO153GOST1976874': - return 'GOST_19768-74'; + case 'csisotextcomm': + case 'iso69372add': + case 'isoir142': + return 'ISO_6937-2-add'; - case 'ISO_8859-SUPP': - case 'ISO-IR-154': - case 'LATIN1-2-5': - case 'CSISO8859SUPP': + case 'csiso8859supp': + case 'iso8859supp': + case 'isoir154': + case 'latin125': return 'ISO_8859-supp'; - case 'ISO_10367-BOX': - case 'ISO-IR-155': - case 'CSISO10367BOX': + case 'csiso10367box': + case 'iso10367box': + case 'isoir155': return 'ISO_10367-box'; - case 'LATIN-LAP': - case 'LAP': - case 'ISO-IR-158': - case 'CSISO158LAP': - return 'latin-lap'; + case 'csiso15italian': + case 'iso646it': + case 'isoir15': + case 'it': + return 'IT'; + + case 'csiso13jisc6220jp': + case 'isoir13': + case 'jisc62201969': + case 'jisc62201969jp': + case 'katakana': + case 'x2017': + return 'JIS_C6220-1969-jp'; + + case 'csiso14jisc6220ro': + case 'iso646jp': + case 'isoir14': + case 'jisc62201969ro': + case 'jp': + return 'JIS_C6220-1969-ro'; + + case 'csiso42jisc62261978': + case 'isoir42': + case 'jisc62261978': + return 'JIS_C6226-1978'; + + case 'csiso87jisx208': + case 'isoir87': + case 'jisc62261983': + case 'jisx2081983': + case 'x208': + return 'JIS_C6226-1983'; + + case 'csiso91jisc62291984a': + case 'isoir91': + case 'jisc62291984a': + case 'jpocra': + return 'JIS_C6229-1984-a'; + + case 'csiso92jisc62991984b': + case 'iso646jpocrb': + case 'isoir92': + case 'jisc62291984b': + case 'jpocrb': + return 'JIS_C6229-1984-b'; + + case 'csiso93jis62291984badd': + case 'isoir93': + case 'jisc62291984badd': + case 'jpocrbadd': + return 'JIS_C6229-1984-b-add'; + + case 'csiso94jis62291984hand': + case 'isoir94': + case 'jisc62291984hand': + case 'jpocrhand': + return 'JIS_C6229-1984-hand'; + + case 'csiso95jis62291984handadd': + case 'isoir95': + case 'jisc62291984handadd': + case 'jpocrhandadd': + return 'JIS_C6229-1984-hand-add'; + + case 'csiso96jisc62291984kana': + case 'isoir96': + case 'jisc62291984kana': + return 'JIS_C6229-1984-kana'; + + case 'csjisencoding': + case 'jisencoding': + return 'JIS_Encoding'; + + case 'cshalfwidthkatakana': + case 'jisx201': + case 'x201': + return 'JIS_X0201'; - case 'JIS_X0212-1990': - case 'X0212': - case 'ISO-IR-159': - case 'CSISO159JISX02121990': + case 'csiso159jisx2121990': + case 'isoir159': + case 'jisx2121990': + case 'x212': return 'JIS_X0212-1990'; - case 'DS_2089': - case 'DS2089': - case 'ISO646-DK': - case 'DK': - case 'CSISO646DANISH': - return 'DS_2089'; + case 'csiso141jusib1002': + case 'iso646yu': + case 'isoir141': + case 'js': + case 'jusib1002': + case 'yu': + return 'JUS_I.B1.002'; - case 'US-DK': - case 'CSUSDK': - return 'us-dk'; + case 'csiso147macedonian': + case 'isoir147': + case 'jusib1003mac': + case 'macedonian': + return 'JUS_I.B1.003-mac'; - case 'DK-US': - case 'CSDKUS': - return 'dk-us'; + case 'csiso146serbian': + case 'isoir146': + case 'jusib1003serb': + case 'serbian': + return 'JUS_I.B1.003-serb'; + + case 'koi7switched': + return 'KOI7-switched'; + + case 'cskoi8r': + case 'koi8r': + return 'KOI8-R'; + + case 'koi8u': + return 'KOI8-U'; - case 'KSC5636': - case 'ISO646-KR': - case 'CSKSC5636': + case 'csksc5636': + case 'iso646kr': + case 'ksc5636': return 'KSC5636'; - case 'UNICODE-1-1-UTF-7': - case 'CSUNICODE11UTF7': - return 'UNICODE-1-1-UTF-7'; + case 'cskz1048': + case 'kz1048': + case 'rk1048': + case 'strk10482002': + return 'KZ-1048'; - case 'ISO-2022-CN': - return 'ISO-2022-CN'; + case 'csiso19latingreek': + case 'isoir19': + case 'latingreek': + return 'latin-greek'; - case 'ISO-2022-CN-EXT': - return 'ISO-2022-CN-EXT'; + case 'csiso27latingreek1': + case 'isoir27': + case 'latingreek1': + return 'Latin-greek-1'; - case 'UTF-8': - return 'UTF-8'; + case 'csiso158lap': + case 'isoir158': + case 'lap': + case 'latinlap': + return 'latin-lap'; - case 'ISO-8859-13': - return 'ISO-8859-13'; + case 'csmacintosh': + case 'mac': + case 'macintosh': + return 'macintosh'; - case 'ISO-8859-14': - case 'ISO-IR-199': - case 'ISO_8859-14:1998': - case 'ISO_8859-14': - case 'LATIN8': - case 'ISO-CELTIC': - case 'L8': - return 'ISO-8859-14'; + case 'csmicrosoftpublishing': + case 'microsoftpublishing': + return 'Microsoft-Publishing'; + + case 'csmnem': + case 'mnem': + return 'MNEM'; + + case 'csmnemonic': + case 'mnemonic': + return 'MNEMONIC'; + + case 'csiso86hungarian': + case 'hu': + case 'iso646hu': + case 'isoir86': + case 'msz77953': + return 'MSZ_7795.3'; + + case 'csnatsdano': + case 'isoir91': + case 'natsdano': + return 'NATS-DANO'; + + case 'csnatsdanoadd': + case 'isoir92': + case 'natsdanoadd': + return 'NATS-DANO-ADD'; + + case 'csnatssefi': + case 'isoir81': + case 'natssefi': + return 'NATS-SEFI'; + + case 'csnatssefiadd': + case 'isoir82': + case 'natssefiadd': + return 'NATS-SEFI-ADD'; - case 'ISO-8859-15': - case 'ISO_8859-15': - case 'LATIN-9': - return 'ISO-8859-15'; + case 'csiso151cuba': + case 'cuba': + case 'iso646cu': + case 'isoir151': + case 'ncnc1081': + return 'NC_NC00-10:81'; - case 'ISO-8859-16': - case 'ISO-IR-226': - case 'ISO_8859-16:2001': - case 'ISO_8859-16': - case 'LATIN10': - case 'L10': - return 'ISO-8859-16'; + case 'csiso69french': + case 'fr': + case 'iso646fr': + case 'isoir69': + case 'nfz62010': + return 'NF_Z_62-010'; - case 'GBK': - case 'CP936': - case 'MS936': - case 'WINDOWS-936': - return 'GBK'; + case 'csiso25french': + case 'iso646fr1': + case 'isoir25': + case 'nfz620101973': + return 'NF_Z_62-010_(1973)'; - case 'GB18030': - return 'GB18030'; + case 'csiso60danishnorwegian': + case 'csiso60norwegian1': + case 'iso646no': + case 'isoir60': + case 'no': + case 'ns45511': + return 'NS_4551-1'; - case 'OSD_EBCDIC_DF04_15': - return 'OSD_EBCDIC_DF04_15'; + case 'csiso61norwegian2': + case 'iso646no2': + case 'isoir61': + case 'no2': + case 'ns45512': + return 'NS_4551-2'; - case 'OSD_EBCDIC_DF03_IRV': + case 'osdebcdicdf3irv': return 'OSD_EBCDIC_DF03_IRV'; - case 'OSD_EBCDIC_DF04_1': + case 'osdebcdicdf41': return 'OSD_EBCDIC_DF04_1'; - case 'ISO-11548-1': - case 'ISO_11548-1': - case 'ISO_TR_11548-1': - case 'CSISO115481': - return 'ISO-11548-1'; - - case 'KZ-1048': - case 'STRK1048-2002': - case 'RK1048': - case 'CSKZ1048': - return 'KZ-1048'; - - case 'ISO-10646-UCS-2': - case 'CSUNICODE': - return 'ISO-10646-UCS-2'; - - case 'ISO-10646-UCS-4': - case 'CSUCS4': - return 'ISO-10646-UCS-4'; + case 'osdebcdicdf415': + return 'OSD_EBCDIC_DF04_15'; - case 'ISO-10646-UCS-BASIC': - case 'CSUNICODEASCII': - return 'ISO-10646-UCS-Basic'; + case 'cspc8danishnorwegian': + case 'pc8danishnorwegian': + return 'PC8-Danish-Norwegian'; - case 'ISO-10646-UNICODE-LATIN1': - case 'CSUNICODELATIN1': - case 'ISO-10646': - return 'ISO-10646-Unicode-Latin1'; + case 'cspc8turkish': + case 'pc8turkish': + return 'PC8-Turkish'; - case 'ISO-10646-J-1': - return 'ISO-10646-J-1'; + case 'csiso16portuguese': + case 'iso646pt': + case 'isoir16': + case 'pt': + return 'PT'; - case 'ISO-UNICODE-IBM-1261': - case 'CSUNICODEIBM1261': - return 'ISO-Unicode-IBM-1261'; + case 'csiso84portuguese2': + case 'iso646pt2': + case 'isoir84': + case 'pt2': + return 'PT2'; - case 'ISO-UNICODE-IBM-1268': - case 'CSUNICODEIBM1268': - return 'ISO-Unicode-IBM-1268'; + case 'cp154': + case 'csptcp154': + case 'cyrillicasian': + case 'pt154': + case 'ptcp154': + return 'PTCP154'; - case 'ISO-UNICODE-IBM-1276': - case 'CSUNICODEIBM1276': - return 'ISO-Unicode-IBM-1276'; + case 'scsu': + return 'SCSU'; - case 'ISO-UNICODE-IBM-1264': - case 'CSUNICODEIBM1264': - return 'ISO-Unicode-IBM-1264'; + case 'csiso10swedish': + case 'fi': + case 'iso646fi': + case 'iso646se': + case 'isoir10': + case 'se': + case 'sen850200b': + return 'SEN_850200_B'; - case 'ISO-UNICODE-IBM-1265': - case 'CSUNICODEIBM1265': - return 'ISO-Unicode-IBM-1265'; + case 'csiso11swedishfornames': + case 'iso646se2': + case 'isoir11': + case 'se2': + case 'sen850200c': + return 'SEN_850200_C'; - case 'UNICODE-1-1': - case 'CSUNICODE11': - return 'UNICODE-1-1'; + case 'csshiftjis': + case 'mskanji': + case 'shiftjis': + return 'Shift_JIS'; - case 'SCSU': - return 'SCSU'; + case 'csiso102t617bit': + case 'isoir102': + case 't617bit': + return 'T.61-7bit'; - case 'UTF-7': - return 'UTF-7'; + case 'csiso103t618bit': + case 'isoir103': + case 't61': + case 't618bit': + return 'T.61-8bit'; - case 'UTF-16BE': - return 'UTF-16BE'; + case 'csiso128t101g2': + case 'isoir128': + case 't101g2': + return 'T.101-G2'; - case 'UTF-16LE': - return 'UTF-16LE'; + case 'cstscii': + case 'tscii': + return 'TSCII'; - case 'UTF-16': - return 'UTF-16'; + case 'csunicode11': + case 'unicode11': + return 'UNICODE-1-1'; - case 'CESU-8': - case 'CSCESU-8': - return 'CESU-8'; + case 'csunicode11utf7': + case 'unicode11utf7': + return 'UNICODE-1-1-UTF-7'; - case 'UTF-32': - return 'UTF-32'; + case 'csunknown8bit': + case 'unknown8bit': + return 'UNKNOWN-8BIT'; - case 'UTF-32BE': - return 'UTF-32BE'; + case 'ansix341968': + case 'ansix341986': + case 'ascii': + case 'cp367': + case 'csascii': + case 'ibm367': + case 'iso646irv1991': + case 'iso646us': + case 'isoir6': + case 'us': + case 'usascii': + return 'US-ASCII'; - case 'UTF-32LE': - return 'UTF-32LE'; + case 'csusdk': + case 'usdk': + return 'us-dk'; - case 'BOCU-1': - case 'CSBOCU-1': - return 'BOCU-1'; + case 'utf7': + return 'UTF-7'; - case 'ISO-8859-1-WINDOWS-3.0-LATIN-1': - case 'CSWINDOWS30LATIN1': - return 'ISO-8859-1-Windows-3.0-Latin-1'; + case 'utf8': + return 'UTF-8'; - case 'ISO-8859-1-WINDOWS-3.1-LATIN-1': - case 'CSWINDOWS31LATIN1': - return 'ISO-8859-1-Windows-3.1-Latin-1'; + case 'utf16': + return 'UTF-16'; - case 'ISO-8859-2-WINDOWS-LATIN-2': - case 'CSWINDOWS31LATIN2': - return 'ISO-8859-2-Windows-Latin-2'; + case 'utf16be': + return 'UTF-16BE'; - case 'ISO-8859-9-WINDOWS-LATIN-5': - case 'CSWINDOWS31LATIN5': - return 'ISO-8859-9-Windows-Latin-5'; + case 'utf16le': + return 'UTF-16LE'; - case 'HP-ROMAN8': - case 'ROMAN8': - case 'R8': - case 'CSHPROMAN8': - return 'hp-roman8'; + case 'utf32': + return 'UTF-32'; - case 'ADOBE-STANDARD-ENCODING': - case 'CSADOBESTANDARDENCODING': - return 'Adobe-Standard-Encoding'; + case 'utf32be': + return 'UTF-32BE'; - case 'VENTURA-US': - case 'CSVENTURAUS': - return 'Ventura-US'; + case 'utf32le': + return 'UTF-32LE'; - case 'VENTURA-INTERNATIONAL': - case 'CSVENTURAINTERNATIONAL': + case 'csventurainternational': + case 'venturainternational': return 'Ventura-International'; - case 'DEC-MCS': - case 'DEC': - case 'CSDECMCS': - return 'DEC-MCS'; - - case 'IBM850': - case 'CP850': - case '850': - case 'CSPC850MULTILINGUAL': - return 'IBM850'; - - case 'PC8-DANISH-NORWEGIAN': - case 'CSPC8DANISHNORWEGIAN': - return 'PC8-Danish-Norwegian'; + case 'csventuramath': + case 'venturamath': + return 'Ventura-Math'; - case 'IBM862': - case 'CP862': - case '862': - case 'CSPC862LATINHEBREW': - return 'IBM862'; + case 'csventuraus': + case 'venturaus': + return 'Ventura-US'; - case 'PC8-TURKISH': - case 'CSPC8TURKISH': - return 'PC8-Turkish'; + case 'csiso70videotexsupp1': + case 'isoir70': + case 'videotexsuppl': + return 'videotex-suppl'; - case 'IBM-SYMBOLS': - case 'CSIBMSYMBOLS': - return 'IBM-Symbols'; + case 'csviqr': + case 'viqr': + return 'VIQR'; - case 'IBM-THAI': - case 'CSIBMTHAI': - return 'IBM-Thai'; + case 'csviscii': + case 'viscii': + return 'VISCII'; - case 'HP-LEGAL': - case 'CSHPLEGAL': - return 'HP-Legal'; + case 'cswindows31j': + case 'windows31j': + return 'Windows-31J'; - case 'HP-PI-FONT': - case 'CSHPPIFONT': - return 'HP-Pi-font'; + case 'iso885911': + case 'tis620': + return 'windows-874'; + + case 'cseuckr': + case 'csksc56011987': + case 'euckr': + case 'isoir149': + case 'korean': + case 'ksc5601': + case 'ksc56011987': + case 'ksc56011989': + case 'windows949': + return 'windows-949'; + + case 'windows1250': + return 'windows-1250'; - case 'HP-MATH8': - case 'CSHPMATH8': - return 'HP-Math8'; + case 'windows1251': + return 'windows-1251'; - case 'ADOBE-SYMBOL-ENCODING': - case 'CSHPPSMATH': - return 'Adobe-Symbol-Encoding'; + case 'cp819': + case 'csisolatin1': + case 'ibm819': + case 'iso88591': + case 'iso885911987': + case 'isoir100': + case 'l1': + case 'latin1': + case 'windows1252': + return 'windows-1252'; - case 'HP-DESKTOP': - case 'CSHPDESKTOP': - return 'HP-DeskTop'; + case 'windows1253': + return 'windows-1253'; - case 'VENTURA-MATH': - case 'CSVENTURAMATH': - return 'Ventura-Math'; + case 'csisolatin5': + case 'iso88599': + case 'iso885991989': + case 'isoir148': + case 'l5': + case 'latin5': + case 'windows1254': + return 'windows-1254'; - case 'MICROSOFT-PUBLISHING': - case 'CSMICROSOFTPUBLISHING': - return 'Microsoft-Publishing'; + case 'windows1255': + return 'windows-1255'; - case 'WINDOWS-31J': - case 'CSWINDOWS31J': - return 'Windows-31J'; + case 'windows1256': + return 'windows-1256'; - case 'GB2312': - case 'CSGB2312': - return 'GB2312'; + case 'windows1257': + return 'windows-1257'; - case 'BIG5': - case 'CSBIG5': - return 'Big5'; + case 'windows1258': + return 'windows-1258'; - case 'MACINTOSH': - case 'MAC': - case 'CSMACINTOSH': - return 'macintosh'; + default: + return $charset; + } + } - case 'IBM037': - case 'CP037': - case 'EBCDIC-CP-US': - case 'EBCDIC-CP-CA': - case 'EBCDIC-CP-WT': - case 'EBCDIC-CP-NL': - case 'CSIBM037': - return 'IBM037'; + function get_curl_version() + { + if (is_array($curl = curl_version())) + { + $curl = $curl['version']; + } + elseif (substr($curl, 0, 5) === 'curl/') + { + $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5)); + } + elseif (substr($curl, 0, 8) === 'libcurl/') + { + $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8)); + } + else + { + $curl = 0; + } + return $curl; + } - case 'IBM038': - case 'EBCDIC-INT': - case 'CP038': - case 'CSIBM038': - return 'IBM038'; + function is_subclass_of($class1, $class2) + { + if (func_num_args() !== 2) + { + trigger_error('Wrong parameter count for SimplePie_Misc::is_subclass_of()', E_USER_WARNING); + } + elseif (version_compare(PHP_VERSION, '5.0.3', '>=') || is_object($class1)) + { + return is_subclass_of($class1, $class2); + } + elseif (is_string($class1) && is_string($class2)) + { + if (class_exists($class1)) + { + if (class_exists($class2)) + { + $class2 = strtolower($class2); + while ($class1 = strtolower(get_parent_class($class1))) + { + if ($class1 === $class2) + { + return true; + } + } + } + } + else + { + trigger_error('Unknown class passed as parameter', E_USER_WARNNG); + } + } + return false; + } - case 'IBM273': - case 'CP273': - case 'CSIBM273': - return 'IBM273'; + /** + * Strip HTML comments + * + * @access public + * @param string $data Data to strip comments from + * @return string Comment stripped string + */ + function strip_comments($data) + { + $output = ''; + while (($start = strpos($data, '', $start)) !== false) + { + $data = substr_replace($data, '', 0, $end + 3); + } + else + { + $data = ''; + } + } + return $output . $data; + } - case 'IBM274': - case 'EBCDIC-BE': - case 'CP274': - case 'CSIBM274': - return 'IBM274'; + function parse_date($dt) + { + $parser = SimplePie_Parse_Date::get(); + return $parser->parse($dt); + } - case 'IBM275': - case 'EBCDIC-BR': - case 'CP275': - case 'CSIBM275': - return 'IBM275'; + /** + * Decode HTML entities + * + * @static + * @access public + * @param string $data Input data + * @return string Output data + */ + function entities_decode($data) + { + $decoder = new SimplePie_Decode_HTML_Entities($data); + return $decoder->parse(); + } - case 'IBM277': - case 'EBCDIC-CP-DK': - case 'EBCDIC-CP-NO': - case 'CSIBM277': - return 'IBM277'; + /** + * Remove RFC822 comments + * + * @access public + * @param string $data Data to strip comments from + * @return string Comment stripped string + */ + function uncomment_rfc822($string) + { + $string = (string) $string; + $position = 0; + $length = strlen($string); + $depth = 0; - case 'IBM278': - case 'CP278': - case 'EBCDIC-CP-FI': - case 'EBCDIC-CP-SE': - case 'CSIBM278': - return 'IBM278'; + $output = ''; - case 'IBM280': - case 'CP280': - case 'EBCDIC-CP-IT': - case 'CSIBM280': - return 'IBM280'; + while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) + { + $output .= substr($string, $position, $pos - $position); + $position = $pos + 1; + if ($string[$pos - 1] !== '\\') + { + $depth++; + while ($depth && $position < $length) + { + $position += strcspn($string, '()', $position); + if ($string[$position - 1] === '\\') + { + $position++; + continue; + } + elseif (isset($string[$position])) + { + switch ($string[$position]) + { + case '(': + $depth++; + break; - case 'IBM281': - case 'EBCDIC-JP-E': - case 'CP281': - case 'CSIBM281': - return 'IBM281'; + case ')': + $depth--; + break; + } + $position++; + } + else + { + break; + } + } + } + else + { + $output .= '('; + } + } + $output .= substr($string, $position); - case 'IBM284': - case 'CP284': - case 'EBCDIC-CP-ES': - case 'CSIBM284': - return 'IBM284'; + return $output; + } - case 'IBM285': - case 'CP285': - case 'EBCDIC-CP-GB': - case 'CSIBM285': - return 'IBM285'; + function parse_mime($mime) + { + if (($pos = strpos($mime, ';')) === false) + { + return trim($mime); + } + else + { + return trim(substr($mime, 0, $pos)); + } + } - case 'IBM290': - case 'CP290': - case 'EBCDIC-JP-KANA': - case 'CSIBM290': - return 'IBM290'; + function htmlspecialchars_decode($string, $quote_style) + { + if (function_exists('htmlspecialchars_decode')) + { + return htmlspecialchars_decode($string, $quote_style); + } + else + { + return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style))); + } + } - case 'IBM297': - case 'CP297': - case 'EBCDIC-CP-FR': - case 'CSIBM297': - return 'IBM297'; + function atom_03_construct_type($attribs) + { + if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64')) + { + $mode = SIMPLEPIE_CONSTRUCT_BASE64; + } + else + { + $mode = SIMPLEPIE_CONSTRUCT_NONE; + } + if (isset($attribs['']['type'])) + { + switch (strtolower(trim($attribs['']['type']))) + { + case 'text': + case 'text/plain': + return SIMPLEPIE_CONSTRUCT_TEXT | $mode; - case 'IBM420': - case 'CP420': - case 'EBCDIC-CP-AR1': - case 'CSIBM420': - return 'IBM420'; + case 'html': + case 'text/html': + return SIMPLEPIE_CONSTRUCT_HTML | $mode; - case 'IBM423': - case 'CP423': - case 'EBCDIC-CP-GR': - case 'CSIBM423': - return 'IBM423'; + case 'xhtml': + case 'application/xhtml+xml': + return SIMPLEPIE_CONSTRUCT_XHTML | $mode; - case 'IBM424': - case 'CP424': - case 'EBCDIC-CP-HE': - case 'CSIBM424': - return 'IBM424'; + default: + return SIMPLEPIE_CONSTRUCT_NONE | $mode; + } + } + else + { + return SIMPLEPIE_CONSTRUCT_TEXT | $mode; + } + } - case 'IBM437': - case 'CP437': - case '437': - case 'CSPC8CODEPAGE437': - return 'IBM437'; + function atom_10_construct_type($attribs) + { + if (isset($attribs['']['type'])) + { + switch (strtolower(trim($attribs['']['type']))) + { + case 'text': + return SIMPLEPIE_CONSTRUCT_TEXT; - case 'IBM500': - case 'CP500': - case 'EBCDIC-CP-BE': - case 'EBCDIC-CP-CH': - case 'CSIBM500': - return 'IBM500'; + case 'html': + return SIMPLEPIE_CONSTRUCT_HTML; - case 'IBM851': - case 'CP851': - case '851': - case 'CSIBM851': - return 'IBM851'; + case 'xhtml': + return SIMPLEPIE_CONSTRUCT_XHTML; - case 'IBM852': - case 'CP852': - case '852': - case 'CSPCP852': - return 'IBM852'; + default: + return SIMPLEPIE_CONSTRUCT_NONE; + } + } + return SIMPLEPIE_CONSTRUCT_TEXT; + } - case 'IBM855': - case 'CP855': - case '855': - case 'CSIBM855': - return 'IBM855'; + function atom_10_content_construct_type($attribs) + { + if (isset($attribs['']['type'])) + { + $type = strtolower(trim($attribs['']['type'])); + switch ($type) + { + case 'text': + return SIMPLEPIE_CONSTRUCT_TEXT; - case 'IBM857': - case 'CP857': - case '857': - case 'CSIBM857': - return 'IBM857'; + case 'html': + return SIMPLEPIE_CONSTRUCT_HTML; - case 'IBM860': - case 'CP860': - case '860': - case 'CSIBM860': - return 'IBM860'; + case 'xhtml': + return SIMPLEPIE_CONSTRUCT_XHTML; + } + if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/') + { + return SIMPLEPIE_CONSTRUCT_NONE; + } + else + { + return SIMPLEPIE_CONSTRUCT_BASE64; + } + } + else + { + return SIMPLEPIE_CONSTRUCT_TEXT; + } + } - case 'IBM861': - case 'CP861': - case '861': - case 'CP-IS': - case 'CSIBM861': - return 'IBM861'; + function is_isegment_nz_nc($string) + { + 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); + } - case 'IBM863': - case 'CP863': - case '863': - case 'CSIBM863': - return 'IBM863'; + function space_seperated_tokens($string) + { + $space_characters = "\x20\x09\x0A\x0B\x0C\x0D"; + $string_length = strlen($string); - case 'IBM864': - case 'CP864': - case 'CSIBM864': - return 'IBM864'; + $position = strspn($string, $space_characters); + $tokens = array(); - case 'IBM865': - case 'CP865': - case '865': - case 'CSIBM865': - return 'IBM865'; + while ($position < $string_length) + { + $len = strcspn($string, $space_characters, $position); + $tokens[] = substr($string, $position, $len); + $position += $len; + $position += strspn($string, $space_characters, $position); + } - case 'IBM868': - case 'CP868': - case 'CP-AR': - case 'CSIBM868': - return 'IBM868'; + return $tokens; + } - case 'IBM869': - case 'CP869': - case '869': - case 'CP-GR': - case 'CSIBM869': - return 'IBM869'; + function array_unique($array) + { + if (version_compare(PHP_VERSION, '5.2', '>=')) + { + return array_unique($array); + } + else + { + $array = (array) $array; + $new_array = array(); + $new_array_strings = array(); + foreach ($array as $key => $value) + { + if (is_object($value)) + { + if (method_exists($value, '__toString')) + { + $cmp = $value->__toString(); + } + else + { + trigger_error('Object of class ' . get_class($value) . ' could not be converted to string', E_USER_ERROR); + } + } + elseif (is_array($value)) + { + $cmp = (string) reset($value); + } + else + { + $cmp = (string) $value; + } + if (!in_array($cmp, $new_array_strings)) + { + $new_array[$key] = $value; + $new_array_strings[] = $cmp; + } + } + return $new_array; + } + } - case 'IBM870': - case 'CP870': - case 'EBCDIC-CP-ROECE': - case 'EBCDIC-CP-YU': - case 'CSIBM870': - return 'IBM870'; + /** + * Converts a unicode codepoint to a UTF-8 character + * + * @static + * @access public + * @param int $codepoint Unicode codepoint + * @return string UTF-8 character + */ + function codepoint_to_utf8($codepoint) + { + $codepoint = (int) $codepoint; + if ($codepoint < 0) + { + return false; + } + else if ($codepoint <= 0x7f) + { + return chr($codepoint); + } + else if ($codepoint <= 0x7ff) + { + return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f)); + } + else if ($codepoint <= 0xffff) + { + return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); + } + else if ($codepoint <= 0x10ffff) + { + return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); + } + else + { + // U+FFFD REPLACEMENT CHARACTER + return "\xEF\xBF\xBD"; + } + } - case 'IBM871': - case 'CP871': - case 'EBCDIC-CP-IS': - case 'CSIBM871': - return 'IBM871'; + /** + * Re-implementation of PHP 5's stripos() + * + * Returns the numeric position of the first occurrence of needle in the + * haystack string. + * + * @static + * @access string + * @param object $haystack + * @param string $needle Note that the needle may be a string of one or more + * characters. If needle is not a string, it is converted to an integer + * and applied as the ordinal value of a character. + * @param int $offset The optional offset parameter allows you to specify which + * character in haystack to start searching. The position returned is still + * relative to the beginning of haystack. + * @return bool If needle is not found, stripos() will return boolean false. + */ + function stripos($haystack, $needle, $offset = 0) + { + if (function_exists('stripos')) + { + return stripos($haystack, $needle, $offset); + } + else + { + if (is_string($needle)) + { + $needle = strtolower($needle); + } + elseif (is_int($needle) || is_bool($needle) || is_double($needle)) + { + $needle = strtolower(chr($needle)); + } + else + { + trigger_error('needle is not a string or an integer', E_USER_WARNING); + return false; + } - case 'IBM880': - case 'CP880': - case 'EBCDIC-CYRILLIC': - case 'CSIBM880': - return 'IBM880'; + return strpos(strtolower($haystack), $needle, $offset); + } + } - case 'IBM891': - case 'CP891': - case 'CSIBM891': - return 'IBM891'; + /** + * Similar to parse_str() + * + * Returns an associative array of name/value pairs, where the value is an + * array of values that have used the same name + * + * @static + * @access string + * @param string $str The input string. + * @return array + */ + function parse_str($str) + { + $return = array(); + $str = explode('&', $str); - case 'IBM903': - case 'CP903': - case 'CSIBM903': - return 'IBM903'; + foreach ($str as $section) + { + if (strpos($section, '=') !== false) + { + list($name, $value) = explode('=', $section, 2); + $return[urldecode($name)][] = urldecode($value); + } + else + { + $return[urldecode($section)][] = null; + } + } - case 'IBM904': - case 'CP904': - case '904': - case 'CSIBBM904': - return 'IBM904'; + return $return; + } - case 'IBM905': - case 'CP905': - case 'EBCDIC-CP-TR': - case 'CSIBM905': - return 'IBM905'; + /** + * Detect XML encoding, as per XML 1.0 Appendix F.1 + * + * @todo Add support for EBCDIC + * @param string $data XML data + * @return array Possible encodings + */ + function xml_encoding($data) + { + // UTF-32 Big Endian BOM + if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") + { + $encoding[] = 'UTF-32BE'; + } + // UTF-32 Little Endian BOM + elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") + { + $encoding[] = 'UTF-32LE'; + } + // UTF-16 Big Endian BOM + elseif (substr($data, 0, 2) === "\xFE\xFF") + { + $encoding[] = 'UTF-16BE'; + } + // UTF-16 Little Endian BOM + elseif (substr($data, 0, 2) === "\xFF\xFE") + { + $encoding[] = 'UTF-16LE'; + } + // UTF-8 BOM + elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") + { + $encoding[] = 'UTF-8'; + } + // UTF-32 Big Endian Without BOM + 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") + { + if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E")) + { + $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-32BE'; + } + // UTF-32 Little Endian Without BOM + 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") + { + if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00")) + { + $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-32LE'; + } + // UTF-16 Big Endian Without BOM + elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C") + { + if ($pos = strpos($data, "\x00\x3F\x00\x3E")) + { + $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-16BE'; + } + // UTF-16 Little Endian Without BOM + elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00") + { + if ($pos = strpos($data, "\x3F\x00\x3E\x00")) + { + $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-16LE'; + } + // US-ASCII (or superset) + elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C") + { + if ($pos = strpos($data, "\x3F\x3E")) + { + $parser = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5)); + if ($parser->parse()) + { + $encoding[] = $parser->encoding; + } + } + $encoding[] = 'UTF-8'; + } + // Fallback to UTF-8 + else + { + $encoding[] = 'UTF-8'; + } + return $encoding; + } - case 'IBM918': - case 'CP918': - case 'EBCDIC-CP-AR2': - case 'CSIBM918': - return 'IBM918'; + function output_javascript() + { + if (function_exists('ob_gzhandler')) + { + ob_start('ob_gzhandler'); + } + header('Content-type: text/javascript; charset: UTF-8'); + header('Cache-Control: must-revalidate'); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days + ?> +function embed_odeo(link) { + document.writeln(''); +} - case 'IBM1026': - case 'CP1026': - case 'CSIBM1026': - return 'IBM1026'; +function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) { + if (placeholder != '') { + document.writeln(''); + } + else { + document.writeln(''); + } +} - case 'EBCDIC-AT-DE': - case 'CSIBMEBCDICATDE': - return 'EBCDIC-AT-DE'; +function embed_flash(bgcolor, width, height, link, loop, type) { + document.writeln(''); +} - case 'EBCDIC-AT-DE-A': - case 'CSEBCDICATDEA': - return 'EBCDIC-AT-DE-A'; +function embed_flv(width, height, link, placeholder, loop, player) { + document.writeln(''); +} - case 'EBCDIC-CA-FR': - case 'CSEBCDICCAFR': - return 'EBCDIC-CA-FR'; +function embed_wmedia(width, height, link) { + document.writeln(''); +} + data = $data; + } - case 'EBCDIC-FR': - case 'CSEBCDICFR': - return 'EBCDIC-FR'; + /** + * Parse the input data + * + * @access public + * @return string Output data + */ + function parse() + { + while (($this->position = strpos($this->data, '&', $this->position)) !== false) + { + $this->consume(); + $this->entity(); + $this->consumed = ''; + } + return $this->data; + } - case 'EBCDIC-IT': - case 'CSEBCDICIT': - return 'EBCDIC-IT'; + /** + * Consume the next byte + * + * @access private + * @return mixed The next byte, or false, if there is no more data + */ + function consume() + { + if (isset($this->data[$this->position])) + { + $this->consumed .= $this->data[$this->position]; + return $this->data[$this->position++]; + } + else + { + return false; + } + } - case 'EBCDIC-PT': - case 'CSEBCDICPT': - return 'EBCDIC-PT'; + /** + * Consume a range of characters + * + * @access private + * @param string $chars Characters to consume + * @return mixed A series of characters that match the range, or false + */ + function consume_range($chars) + { + if ($len = strspn($this->data, $chars, $this->position)) + { + $data = substr($this->data, $this->position, $len); + $this->consumed .= $data; + $this->position += $len; + return $data; + } + else + { + return false; + } + } - case 'EBCDIC-ES': - case 'CSEBCDICES': - return 'EBCDIC-ES'; + /** + * Unconsume one byte + * + * @access private + */ + function unconsume() + { + $this->consumed = substr($this->consumed, 0, -1); + $this->position--; + } - case 'EBCDIC-ES-A': - case 'CSEBCDICESA': - return 'EBCDIC-ES-A'; + /** + * Decode an entity + * + * @access private + */ + function entity() + { + switch ($this->consume()) + { + case "\x09": + case "\x0A": + case "\x0B": + case "\x0B": + case "\x0C": + case "\x20": + case "\x3C": + case "\x26": + case false: + break; - case 'EBCDIC-ES-S': - case 'CSEBCDICESS': - return 'EBCDIC-ES-S'; + case "\x23": + switch ($this->consume()) + { + case "\x78": + case "\x58": + $range = '0123456789ABCDEFabcdef'; + $hex = true; + break; - case 'EBCDIC-UK': - case 'CSEBCDICUK': - return 'EBCDIC-UK'; + default: + $range = '0123456789'; + $hex = false; + $this->unconsume(); + break; + } - case 'EBCDIC-US': - case 'CSEBCDICUS': - return 'EBCDIC-US'; + if ($codepoint = $this->consume_range($range)) + { + 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"); - case 'UNKNOWN-8BIT': - case 'CSUNKNOWN8BIT': - return 'UNKNOWN-8BIT'; + if ($hex) + { + $codepoint = hexdec($codepoint); + } + else + { + $codepoint = intval($codepoint); + } - case 'MNEMONIC': - case 'CSMNEMONIC': - return 'MNEMONIC'; + if (isset($windows_1252_specials[$codepoint])) + { + $replacement = $windows_1252_specials[$codepoint]; + } + else + { + $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint); + } - case 'MNEM': - case 'CSMNEM': - return 'MNEM'; + if (!in_array($this->consume(), array(';', false), true)) + { + $this->unconsume(); + } - case 'VISCII': - case 'CSVISCII': - return 'VISCII'; + $consumed_length = strlen($this->consumed); + $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length); + $this->position += strlen($replacement) - $consumed_length; + } + break; - case 'VIQR': - case 'CSVIQR': - return 'VIQR'; + default: + 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"); - case 'KOI8-R': - case 'CSKOI8R': - return 'KOI8-R'; + for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++) + { + $consumed = substr($this->consumed, 1); + if (isset($entities[$consumed])) + { + $match = $consumed; + } + } - case 'HZ-GB-2312': - return 'HZ-GB-2312'; + if ($match !== null) + { + $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1); + $this->position += strlen($entities[$match]) - strlen($consumed) - 1; + } + break; + } + } +} - case 'IBM866': - case 'CP866': - case '866': - case 'CSIBM866': - return 'IBM866'; +/** + * IRI parser/serialiser + * + * @package SimplePie + */ +class SimplePie_IRI +{ + /** + * Scheme + * + * @access private + * @var string + */ + var $scheme; - case 'IBM775': - case 'CP775': - case 'CSPC775BALTIC': - return 'IBM775'; + /** + * User Information + * + * @access private + * @var string + */ + var $userinfo; - case 'KOI8-U': - return 'KOI8-U'; + /** + * Host + * + * @access private + * @var string + */ + var $host; - case 'IBM00858': - case 'CCSID00858': - case 'CP00858': - case 'PC-MULTILINGUAL-850+EURO': - return 'IBM00858'; + /** + * Port + * + * @access private + * @var string + */ + var $port; - case 'IBM00924': - case 'CCSID00924': - case 'CP00924': - case 'EBCDIC-LATIN9--EURO': - return 'IBM00924'; + /** + * Path + * + * @access private + * @var string + */ + var $path; - case 'IBM01140': - case 'CCSID01140': - case 'CP01140': - case 'EBCDIC-US-37+EURO': - return 'IBM01140'; + /** + * Query + * + * @access private + * @var string + */ + var $query; - case 'IBM01141': - case 'CCSID01141': - case 'CP01141': - case 'EBCDIC-DE-273+EURO': - return 'IBM01141'; + /** + * Fragment + * + * @access private + * @var string + */ + var $fragment; - case 'IBM01142': - case 'CCSID01142': - case 'CP01142': - case 'EBCDIC-DK-277+EURO': - case 'EBCDIC-NO-277+EURO': - return 'IBM01142'; + /** + * Whether the object represents a valid IRI + * + * @access private + * @var array + */ + var $valid = array(); - case 'IBM01143': - case 'CCSID01143': - case 'CP01143': - case 'EBCDIC-FI-278+EURO': - case 'EBCDIC-SE-278+EURO': - return 'IBM01143'; + /** + * Return the entire IRI when you try and read the object as a string + * + * @access public + * @return string + */ + function __toString() + { + return $this->get_iri(); + } - case 'IBM01144': - case 'CCSID01144': - case 'CP01144': - case 'EBCDIC-IT-280+EURO': - return 'IBM01144'; + /** + * Create a new IRI object, from a specified string + * + * @access public + * @param string $iri + * @return SimplePie_IRI + */ + function SimplePie_IRI($iri) + { + $iri = (string) $iri; + if ($iri !== '') + { + $parsed = $this->parse_iri($iri); + $this->set_scheme($parsed['scheme']); + $this->set_authority($parsed['authority']); + $this->set_path($parsed['path']); + $this->set_query($parsed['query']); + $this->set_fragment($parsed['fragment']); + } + } - case 'IBM01145': - case 'CCSID01145': - case 'CP01145': - case 'EBCDIC-ES-284+EURO': - return 'IBM01145'; + /** + * Create a new IRI object by resolving a relative IRI + * + * @static + * @access public + * @param SimplePie_IRI $base Base IRI + * @param string $relative Relative IRI + * @return SimplePie_IRI + */ + function absolutize($base, $relative) + { + $relative = (string) $relative; + if ($relative !== '') + { + $relative = new SimplePie_IRI($relative); + if ($relative->get_scheme() !== null) + { + $target = $relative; + } + elseif ($base->get_iri() !== null) + { + if ($relative->get_authority() !== null) + { + $target = $relative; + $target->set_scheme($base->get_scheme()); + } + else + { + $target = new SimplePie_IRI(''); + $target->set_scheme($base->get_scheme()); + $target->set_userinfo($base->get_userinfo()); + $target->set_host($base->get_host()); + $target->set_port($base->get_port()); + if ($relative->get_path() !== null) + { + if (strpos($relative->get_path(), '/') === 0) + { + $target->set_path($relative->get_path()); + } + elseif (($base->get_userinfo() !== null || $base->get_host() !== null || $base->get_port() !== null) && $base->get_path() === null) + { + $target->set_path('/' . $relative->get_path()); + } + elseif (($last_segment = strrpos($base->get_path(), '/')) !== false) + { + $target->set_path(substr($base->get_path(), 0, $last_segment + 1) . $relative->get_path()); + } + else + { + $target->set_path($relative->get_path()); + } + $target->set_query($relative->get_query()); + } + else + { + $target->set_path($base->get_path()); + if ($relative->get_query() !== null) + { + $target->set_query($relative->get_query()); + } + elseif ($base->get_query() !== null) + { + $target->set_query($base->get_query()); + } + } + } + $target->set_fragment($relative->get_fragment()); + } + else + { + // No base URL, just return the relative URL + $target = $relative; + } + } + else + { + $target = $base; + } + return $target; + } - case 'IBM01146': - case 'CCSID01146': - case 'CP01146': - case 'EBCDIC-GB-285+EURO': - return 'IBM01146'; + /** + * Parse an IRI into scheme/authority/path/query/fragment segments + * + * @access private + * @param string $iri + * @return array + */ + function parse_iri($iri) + { + preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/', $iri, $match); + for ($i = count($match); $i <= 9; $i++) + { + $match[$i] = ''; + } + return array('scheme' => $match[2], 'authority' => $match[4], 'path' => $match[5], 'query' => $match[7], 'fragment' => $match[9]); + } - case 'IBM01147': - case 'CCSID01147': - case 'CP01147': - case 'EBCDIC-FR-297+EURO': - return 'IBM01147'; + /** + * Remove dot segments from a path + * + * @access private + * @param string $input + * @return string + */ + function remove_dot_segments($input) + { + $output = ''; + while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') + { + // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise, + if (strpos($input, '../') === 0) + { + $input = substr($input, 3); + } + elseif (strpos($input, './') === 0) + { + $input = substr($input, 2); + } + // 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, + elseif (strpos($input, '/./') === 0) + { + $input = substr_replace($input, '/', 0, 3); + } + elseif ($input === '/.') + { + $input = '/'; + } + // 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, + elseif (strpos($input, '/../') === 0) + { + $input = substr_replace($input, '/', 0, 4); + $output = substr_replace($output, '', strrpos($output, '/')); + } + elseif ($input === '/..') + { + $input = '/'; + $output = substr_replace($output, '', strrpos($output, '/')); + } + // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise, + elseif ($input === '.' || $input === '..') + { + $input = ''; + } + // 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 + elseif (($pos = strpos($input, '/', 1)) !== false) + { + $output .= substr($input, 0, $pos); + $input = substr_replace($input, '', 0, $pos); + } + else + { + $output .= $input; + $input = ''; + } + } + return $output . $input; + } - case 'IBM01148': - case 'CCSID01148': - case 'CP01148': - case 'EBCDIC-INTERNATIONAL-500+EURO': - return 'IBM01148'; + /** + * Replace invalid character with percent encoding + * + * @access private + * @param string $string Input string + * @param string $valid_chars Valid characters + * @param int $case Normalise case + * @return string + */ + function replace_invalid_with_pct_encoding($string, $valid_chars, $case = SIMPLEPIE_SAME_CASE) + { + // Normalise case + if ($case & SIMPLEPIE_LOWERCASE) + { + $string = strtolower($string); + } + elseif ($case & SIMPLEPIE_UPPERCASE) + { + $string = strtoupper($string); + } - case 'IBM01149': - case 'CCSID01149': - case 'CP01149': - case 'EBCDIC-IS-871+EURO': - return 'IBM01149'; + // Store position and string length (to avoid constantly recalculating this) + $position = 0; + $strlen = strlen($string); - case 'BIG5-HKSCS': - return 'Big5-HKSCS'; + // Loop as long as we have invalid characters, advancing the position to the next invalid character + while (($position += strspn($string, $valid_chars, $position)) < $strlen) + { + // If we have a % character + if ($string[$position] === '%') + { + // If we have a pct-encoded section + if ($position + 2 < $strlen && strspn($string, '0123456789ABCDEFabcdef', $position + 1, 2) === 2) + { + // Get the the represented character + $chr = chr(hexdec(substr($string, $position + 1, 2))); - case 'IBM1047': - case 'IBM-1047': - return 'IBM1047'; + // If the character is valid, replace the pct-encoded with the actual character while normalising case + if (strpos($valid_chars, $chr) !== false) + { + if ($case & SIMPLEPIE_LOWERCASE) + { + $chr = strtolower($chr); + } + elseif ($case & SIMPLEPIE_UPPERCASE) + { + $chr = strtoupper($chr); + } + $string = substr_replace($string, $chr, $position, 3); + $strlen -= 2; + $position++; + } - case 'PTCP154': - case 'CSPTCP154': - case 'PT154': - case 'CP154': - case 'CYRILLIC-ASIAN': - return 'PTCP154'; + // Otherwise just normalise the pct-encoded to uppercase + else + { + $string = substr_replace($string, strtoupper(substr($string, $position + 1, 2)), $position + 1, 2); + $position += 3; + } + } + // If we don't have a pct-encoded section, just replace the % with its own esccaped form + else + { + $string = substr_replace($string, '%25', $position, 1); + $strlen += 2; + $position += 3; + } + } + // If we have an invalid character, change into its pct-encoded form + else + { + $replacement = sprintf("%%%02X", ord($string[$position])); + $string = str_replace($string[$position], $replacement, $string); + $strlen = strlen($string); + } + } + return $string; + } - case 'AMIGA-1251': - case 'AMI1251': - case 'AMIGA1251': - case 'AMI-1251': - return 'Amiga-1251'; + /** + * Check if the object represents a valid IRI + * + * @access public + * @return bool + */ + function is_valid() + { + return array_sum($this->valid) === count($this->valid); + } - case 'KOI7-SWITCHED': - return 'KOI7-switched'; + /** + * Set the scheme. Returns true on success, false on failure (if there are + * any invalid characters). + * + * @access public + * @param string $scheme + * @return bool + */ + function set_scheme($scheme) + { + if ($scheme === null || $scheme === '') + { + $this->scheme = null; + } + else + { + $len = strlen($scheme); + switch (true) + { + case $len > 1: + if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-.', 1)) + { + $this->scheme = null; + $this->valid[__FUNCTION__] = false; + return false; + } - case 'BRF': - case 'CSBRF': - return 'BRF'; + case $len > 0: + if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 0, 1)) + { + $this->scheme = null; + $this->valid[__FUNCTION__] = false; + return false; + } + } + $this->scheme = strtolower($scheme); + } + $this->valid[__FUNCTION__] = true; + return true; + } - case 'TSCII': - case 'CSTSCII': - return 'TSCII'; + /** + * Set the authority. Returns true on success, false on failure (if there are + * any invalid characters). + * + * @access public + * @param string $authority + * @return bool + */ + function set_authority($authority) + { + if (($userinfo_end = strrpos($authority, '@')) !== false) + { + $userinfo = substr($authority, 0, $userinfo_end); + $authority = substr($authority, $userinfo_end + 1); + } + else + { + $userinfo = null; + } - case 'WINDOWS-1250': - return 'windows-1250'; + if (($port_start = strpos($authority, ':')) !== false) + { + $port = substr($authority, $port_start + 1); + $authority = substr($authority, 0, $port_start); + } + else + { + $port = null; + } - case 'WINDOWS-1251': - return 'windows-1251'; + return $this->set_userinfo($userinfo) && $this->set_host($authority) && $this->set_port($port); + } - case 'WINDOWS-1252': - return 'windows-1252'; + /** + * Set the userinfo. + * + * @access public + * @param string $userinfo + * @return bool + */ + function set_userinfo($userinfo) + { + if ($userinfo === null || $userinfo === '') + { + $this->userinfo = null; + } + else + { + $this->userinfo = $this->replace_invalid_with_pct_encoding($userinfo, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:'); + } + $this->valid[__FUNCTION__] = true; + return true; + } - case 'WINDOWS-1253': - return 'windows-1253'; + /** + * Set the host. Returns true on success, false on failure (if there are + * any invalid characters). + * + * @access public + * @param string $host + * @return bool + */ + function set_host($host) + { + if ($host === null || $host === '') + { + $this->host = null; + $this->valid[__FUNCTION__] = true; + return true; + } + elseif ($host[0] === '[' && substr($host, -1) === ']') + { + if (Net_IPv6::checkIPv6(substr($host, 1, -1))) + { + $this->host = $host; + $this->valid[__FUNCTION__] = true; + return true; + } + else + { + $this->host = null; + $this->valid[__FUNCTION__] = false; + return false; + } + } + else + { + $this->host = $this->replace_invalid_with_pct_encoding($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=', SIMPLEPIE_LOWERCASE); + $this->valid[__FUNCTION__] = true; + return true; + } + } - case 'WINDOWS-1254': - return 'windows-1254'; + /** + * Set the port. Returns true on success, false on failure (if there are + * any invalid characters). + * + * @access public + * @param string $port + * @return bool + */ + function set_port($port) + { + if ($port === null || $port === '') + { + $this->port = null; + $this->valid[__FUNCTION__] = true; + return true; + } + elseif (strspn($port, '0123456789') === strlen($port)) + { + $this->port = (int) $port; + $this->valid[__FUNCTION__] = true; + return true; + } + else + { + $this->port = null; + $this->valid[__FUNCTION__] = false; + return false; + } + } - case 'WINDOWS-1255': - return 'windows-1255'; + /** + * Set the path. + * + * @access public + * @param string $path + * @return bool + */ + function set_path($path) + { + if ($path === null || $path === '') + { + $this->path = null; + $this->valid[__FUNCTION__] = true; + return true; + } + elseif (substr($path, 0, 2) === '//' && $this->userinfo === null && $this->host === null && $this->port === null) + { + $this->path = null; + $this->valid[__FUNCTION__] = false; + return false; + } + else + { + $this->path = $this->replace_invalid_with_pct_encoding($path, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=@/'); + if ($this->scheme !== null) + { + $this->path = $this->remove_dot_segments($this->path); + } + $this->valid[__FUNCTION__] = true; + return true; + } + } - case 'WINDOWS-1256': - return 'windows-1256'; + /** + * Set the query. + * + * @access public + * @param string $query + * @return bool + */ + function set_query($query) + { + if ($query === null || $query === '') + { + $this->query = null; + } + else + { + $this->query = $this->replace_invalid_with_pct_encoding($query, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$\'()*+,;:@/?'); + } + $this->valid[__FUNCTION__] = true; + return true; + } - case 'WINDOWS-1257': - return 'windows-1257'; + /** + * Set the fragment. + * + * @access public + * @param string $fragment + * @return bool + */ + function set_fragment($fragment) + { + if ($fragment === null || $fragment === '') + { + $this->fragment = null; + } + else + { + $this->fragment = $this->replace_invalid_with_pct_encoding($fragment, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:@/?'); + } + $this->valid[__FUNCTION__] = true; + return true; + } - case 'WINDOWS-1258': - return 'windows-1258'; + /** + * Get the complete IRI + * + * @access public + * @return string + */ + function get_iri() + { + $iri = ''; + if ($this->scheme !== null) + { + $iri .= $this->scheme . ':'; + } + if (($authority = $this->get_authority()) !== null) + { + $iri .= '//' . $authority; + } + if ($this->path !== null) + { + $iri .= $this->path; + } + if ($this->query !== null) + { + $iri .= '?' . $this->query; + } + if ($this->fragment !== null) + { + $iri .= '#' . $this->fragment; + } - default: - return (string) $encoding; + if ($iri !== '') + { + return $iri; + } + else + { + return null; } } - function get_curl_version() + /** + * Get the scheme + * + * @access public + * @return string + */ + function get_scheme() { - if (is_array($curl = curl_version())) + return $this->scheme; + } + + /** + * Get the complete authority + * + * @access public + * @return string + */ + function get_authority() + { + $authority = ''; + if ($this->userinfo !== null) { - $curl = $curl['version']; + $authority .= $this->userinfo . '@'; } - elseif (substr($curl, 0, 5) == 'curl/') + if ($this->host !== null) { - $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5)); + $authority .= $this->host; } - elseif (substr($curl, 0, 8) == 'libcurl/') + if ($this->port !== null) { - $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8)); + $authority .= ':' . $this->port; + } + + if ($authority !== '') + { + return $authority; } else { - $curl = 0; + return null; } - return $curl; } - function is_subclass_of($class1, $class2) + /** + * Get the user information + * + * @access public + * @return string + */ + function get_userinfo() + { + return $this->userinfo; + } + + /** + * Get the host + * + * @access public + * @return string + */ + function get_host() { - if (func_num_args() != 2) + return $this->host; + } + + /** + * Get the port + * + * @access public + * @return string + */ + function get_port() + { + return $this->port; + } + + /** + * Get the path + * + * @access public + * @return string + */ + function get_path() + { + return $this->path; + } + + /** + * Get the query + * + * @access public + * @return string + */ + function get_query() + { + return $this->query; + } + + /** + * Get the fragment + * + * @access public + * @return string + */ + function get_fragment() + { + return $this->fragment; + } +} + +/** + * Class to validate and to work with IPv6 addresses. + * + * @package SimplePie + * @copyright 2003-2005 The PHP Group + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/package/Net_IPv6 + * @author Alexander Merz + * @author elfrink at introweb dot nl + * @author Josh Peck + * @author Geoffrey Sneddon + */ +class SimplePie_Net_IPv6 +{ + /** + * Removes a possible existing netmask specification of an IP address. + * + * @param string $ip the (compressed) IP as Hex representation + * @return string the IP the without netmask + * @since 1.1.0 + * @access public + * @static + */ + function removeNetmaskSpec($ip) + { + if (strpos($ip, '/') !== false) { - trigger_error('Wrong parameter count for SimplePie_Misc::is_subclass_of()', E_USER_WARNING); + list($addr, $nm) = explode('/', $ip); } - elseif (version_compare(PHP_VERSION, '5.0.3', '>=') || is_object($class1)) + else { - return is_subclass_of($class1, $class2); + $addr = $ip; } - elseif (is_string($class1) && is_string($class2)) + return $addr; + } + + /** + * Uncompresses an IPv6 address + * + * RFC 2373 allows you to compress zeros in an address to '::'. This + * function expects an valid IPv6 address and expands the '::' to + * the required zeros. + * + * Example: FF01::101 -> FF01:0:0:0:0:0:0:101 + * ::1 -> 0:0:0:0:0:0:0:1 + * + * @access public + * @static + * @param string $ip a valid IPv6-address (hex format) + * @return string the uncompressed IPv6-address (hex format) + */ + function Uncompress($ip) + { + $uip = SimplePie_Net_IPv6::removeNetmaskSpec($ip); + $c1 = -1; + $c2 = -1; + if (strpos($ip, '::') !== false) { - if (class_exists($class1)) + list($ip1, $ip2) = explode('::', $ip); + if ($ip1 === '') + { + $c1 = -1; + } + else + { + $pos = 0; + if (($pos = substr_count($ip1, ':')) > 0) + { + $c1 = $pos; + } + else + { + $c1 = 0; + } + } + if ($ip2 === '') { - if (class_exists($class2)) + $c2 = -1; + } + else + { + $pos = 0; + if (($pos = substr_count($ip2, ':')) > 0) { - $class2 = strtolower($class2); - while ($class1 = strtolower(get_parent_class($class1))) - { - if ($class1 == $class2) - { - return true; - } - } + $c2 = $pos; + } + else + { + $c2 = 0; } } + if (strstr($ip2, '.')) + { + $c2++; + } + // :: + if ($c1 === -1 && $c2 === -1) + { + $uip = '0:0:0:0:0:0:0:0'; + } + // ::xxx + else if ($c1 === -1) + { + $fill = str_repeat('0:', 7 - $c2); + $uip = str_replace('::', $fill, $uip); + } + // xxx:: + else if ($c2 === -1) + { + $fill = str_repeat(':0', 7 - $c1); + $uip = str_replace('::', $fill, $uip); + } + // xxx::xxx else { - trigger_error('Unknown class passed as parameter', E_USER_WARNING); + $fill = str_repeat(':0:', 6 - $c2 - $c1); + $uip = str_replace('::', $fill, $uip); + $uip = str_replace('::', ':', $uip); } } - return false; + return $uip; } /** - * Strip HTML comments + * Splits an IPv6 address into the IPv6 and a possible IPv4 part + * + * RFC 2373 allows you to note the last two parts of an IPv6 address as + * an IPv4 compatible address + * + * Example: 0:0:0:0:0:0:13.1.68.3 + * 0:0:0:0:0:FFFF:129.144.52.38 * * @access public - * @param string $data Data to strip comments from - * @return string Comment stripped string + * @static + * @param string $ip a valid IPv6-address (hex format) + * @return array [0] contains the IPv6 part, [1] the IPv4 part (hex format) */ - function strip_comments($data) + function SplitV64($ip) { - $output = ''; - while (($start = strpos($data, '', $start)) !== false) - { - $data = substr_replace($data, '', 0, $end + 3); - } - else - { - $data = ''; - } + $pos = strrpos($ip, ':'); + $ip[$pos] = '_'; + $ipPart = explode('_', $ip); + return $ipPart; + } + else + { + return array($ip, ''); } - return $output . $data; } - function parse_date($dt, $rfc822_tz = true) + /** + * Checks an IPv6 address + * + * Checks if the given IP is IPv6-compatible + * + * @access public + * @static + * @param string $ip a valid IPv6-address + * @return bool true if $ip is an IPv6 address + */ + function checkIPv6($ip) { - static $cache = array(); - if (!isset($cache[$dt][$rfc822_tz])) + $ipPart = SimplePie_Net_IPv6::SplitV64($ip); + $count = 0; + if (!empty($ipPart[0])) { - $dt = SimplePie_Misc::uncomment_rfc822($dt); - /* - Capturing subpatterns: - 1: RFC 822 date - 2: RFC 822 day - 3: RFC 822 month - 4: RFC 822 year - 5: ISO 8601 date - 6: ISO 8601 century - 7: ISO 8601 year - 8: ISO 8601 month - 9: ISO 8601 day - 10: ISO 8601 ordinal day - 11: ISO 8601 month - 12: ISO 8601 day - 13: ISO 8601 week - 14: ISO 8601 day of week - 15: Time - 16: Hour - 17: Hour Decimal - 18: Minute - 19: Minute Decimal - 20: Second - 21: Second Decimal - 22: Timezone - 23: Diff ± - 24: Hour - 25: Hour Decimal - 26: Minute - 27: Minute Decimal - 28: Alphabetic Timezone - */ - if (preg_match('/^(?:(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)[,\s]+)?(([0-9]{1,2})\s*(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s*([0-9]{4}|[0-9]{2}))|(([0-9]{2})(?:([0-9]{2})(?:(?:-|\s)*(?:([0-9]{2})([0-9]{2})|([0-9]{3})|([0-9]{2})(?:(?:-|\s)*([0-9]{2}))?|W([0-9]{2})(?:(?:-|\s)*([0-9]))?))?)?))((?:T|\s)+([0-9]{2})(?:(?:,|\.)([0-9]*)|(?:\:|\s)*([0-9]{2})(?:(?:,|\.)([0-9]*)|(?:\:|\s)*([0-9]{2})(?:(?:,|\.)([0-9]*))?)?)?(?:\s)*((?:(\+|-)([0-9]{2})(?:(?:,|\.)([0-9]*)|(?:\:|\s)*(?:([0-9]{2})(?:(?:,|\.)([0-9]*))?))?)|(UTC|GMT|EST|CST|MST|PST|EDT|CDT|MDT|PDT|UT|[A-IK-Z]))?)?$/i', $dt, $match)) + $ipv6 = explode(':', $ipPart[0]); + for ($i = 0; $i < count($ipv6); $i++) { - // Fill all matches - for ($i = count($match); $i <= 28; $i++) + $dec = hexdec($ipv6[$i]); + $hex = strtoupper(preg_replace('/^[0]{1,3}(.*[0-9a-fA-F])$/', '\\1', $ipv6[$i])); + if ($ipv6[$i] >= 0 && $dec <= 65535 && $hex === strtoupper(dechex($dec))) { - $match[$i] = ''; + $count++; } - - // Set blank vars - $year = 1970; - $month = 1; - $day = 1; - $hour = 0; - $minute = 0; - $second = 0; - $timezone = false; - - // RFC 822 - if ($match[1] !== '') + } + if ($count === 8) + { + return true; + } + elseif ($count === 6 && !empty($ipPart[1])) + { + $ipv4 = explode('.', $ipPart[1]); + $count = 0; + foreach ($ipv4 as $ipv4_part) { - if (strlen($match[4]) == 2) - { - $year = ($match[4] < 70) ? "20$match[4]" : "19$match[4]"; - } - else + if ($ipv4_part >= 0 && $ipv4_part <= 255 && preg_match('/^\d{1,3}$/', $ipv4_part)) { - $year = $match[4]; - } - switch (strtolower($match[3])) - { - case 'jan': - $month = 1; - break; - - case 'feb': - $month = 2; - break; - - case 'mar': - $month = 3; - break; - - case 'apr': - $month = 4; - break; - - case 'may': - $month = 5; - break; - - case 'jun': - $month = 6; - break; - - case 'jul': - $month = 7; - break; - - case 'aug': - $month = 8; - break; - - case 'sep': - $month = 9; - break; - - case 'oct': - $month = 10; - break; - - case 'nov': - $month = 11; - break; - - case 'dec': - $month = 12; - break; + $count++; } - $day = $match[2]; } - // ISO 8601 - else + if ($count === 4) { - // Year - if ($match[7] !== '') - { - $year = "$match[6]$match[7]"; - - // Two Digit Month/Day - if ($match[11] !== '') - { - $month = $match[11]; - if ($match[12] !== '') - { - $day = $match[12]; - } - } - - // Four Digit Month/Day - elseif ($match[8] !== '') - { - $month = $match[8]; - $day = $match[9]; - } - - // Ordinal Day - elseif ($match[10] !== '') - { - $day = $match[10]; - } - - // Week Date - elseif ($match[13] !== '') - { - // Week Day - if ($match[14] !== '') - { - $day = $match[14]; - } - - $first_day_of_year = date('w', mktime(0, 0, 0, 1, 1, $year)); - if ($first_day_of_year == 0) - { - $first_day_of_year = 7; - } - - $day = 7 * ($match[13] - 1) + $day - ($first_day_of_year - 1); - } - } - else - { - $year = "$match[6]00"; - } + return true; } - // Time - if ($match[15] !== '') - { - $time = 0; - $time += ($match[16] + ('.' . $match[17])) * 3600; - $time += ($match[18] + ('.' . $match[19])) * 60; - $time += $match[20] + ('.' . $match[21]); - $hour = floor($time / 3600); - $time -= $hour * 3600; - $minute = floor($time / 60); - $time -= $minute * 60; - $second = round($time); - - // Timezone - if ($match[22] !== '') - { - // Alphabetic Timezone - if ($match[28] !== '') - { - // Military - if (strlen($match[28]) == 1) - { - if ($match[28] == 'Z' || $match[28] == 'z' || !$rfc822_tz) - { - $timezone = 0; - } - else - { - $timezone = ord(strtoupper($match[28])); + } + else + { + return false; + } - if ($timezone > 74) - { - $timezone--; - } + } + else + { + return false; + } + } +} - if ($timezone <= 76) - { - $timezone = -($timezone - 64); - } - else - { - $timezone -= 76; - } +/** + * Date Parser + * + * @package SimplePie + */ +class SimplePie_Parse_Date +{ + /** + * Input data + * + * @access protected + * @var string + */ + var $date; - $timezone *= 3600; - } - } - // Code - else - { - switch (strtoupper($match[28])) - { - case 'UT': - case 'UTC': - case 'GMT': - $timezone = 0; - break; + /** + * List of days, calendar day name => ordinal day number in the week + * + * @access protected + * @var array + */ + var $day = array( + // English + 'mon' => 1, + 'monday' => 1, + 'tue' => 2, + 'tuesday' => 2, + 'wed' => 3, + 'wednesday' => 3, + 'thu' => 4, + 'thursday' => 4, + 'fri' => 5, + 'friday' => 5, + 'sat' => 6, + 'saturday' => 6, + 'sun' => 7, + 'sunday' => 7, + // Dutch + 'maandag' => 1, + 'dinsdag' => 2, + 'woensdag' => 3, + 'donderdag' => 4, + 'vrijdag' => 5, + 'zaterdag' => 6, + 'zondag' => 7, + // French + 'lundi' => 1, + 'mardi' => 2, + 'mercredi' => 3, + 'jeudi' => 4, + 'vendredi' => 5, + 'samedi' => 6, + 'dimanche' => 7, + // German + 'montag' => 1, + 'dienstag' => 2, + 'mittwoch' => 3, + 'donnerstag' => 4, + 'freitag' => 5, + 'samstag' => 6, + 'sonnabend' => 6, + 'sonntag' => 7, + // Italian + 'lunedì' => 1, + 'martedì' => 2, + 'mercoledì' => 3, + 'giovedì' => 4, + 'venerdì' => 5, + 'sabato' => 6, + 'domenica' => 7, + // Spanish + 'lunes' => 1, + 'martes' => 2, + 'miércoles' => 3, + 'jueves' => 4, + 'viernes' => 5, + 'sábado' => 6, + 'domingo' => 7, + // Finnish + 'maanantai' => 1, + 'tiistai' => 2, + 'keskiviikko' => 3, + 'torstai' => 4, + 'perjantai' => 5, + 'lauantai' => 6, + 'sunnuntai' => 7, + // Hungarian + 'hétfő' => 1, + 'kedd' => 2, + 'szerda' => 3, + 'csütörtok' => 4, + 'péntek' => 5, + 'szombat' => 6, + 'vasárnap' => 7, + // Greek + 'Δευ' => 1, + 'Τρι' => 2, + 'Τετ' => 3, + 'Πεμ' => 4, + 'Παρ' => 5, + 'Σαβ' => 6, + 'Κυρ' => 7, + ); - case 'EST': - $timezone = -18000; - break; + /** + * List of months, calendar month name => calendar month number + * + * @access protected + * @var array + */ + var $month = array( + // English + 'jan' => 1, + 'january' => 1, + 'feb' => 2, + 'february' => 2, + 'mar' => 3, + 'march' => 3, + 'apr' => 4, + 'april' => 4, + 'may' => 5, + // No long form of May + 'jun' => 6, + 'june' => 6, + 'jul' => 7, + 'july' => 7, + 'aug' => 8, + 'august' => 8, + 'sep' => 9, + 'september' => 8, + 'oct' => 10, + 'october' => 10, + 'nov' => 11, + 'november' => 11, + 'dec' => 12, + 'december' => 12, + // Dutch + 'januari' => 1, + 'februari' => 2, + 'maart' => 3, + 'april' => 4, + 'mei' => 5, + 'juni' => 6, + 'juli' => 7, + 'augustus' => 8, + 'september' => 9, + 'oktober' => 10, + 'november' => 11, + 'december' => 12, + // French + 'janvier' => 1, + 'février' => 2, + 'mars' => 3, + 'avril' => 4, + 'mai' => 5, + 'juin' => 6, + 'juillet' => 7, + 'août' => 8, + 'septembre' => 9, + 'octobre' => 10, + 'novembre' => 11, + 'décembre' => 12, + // German + 'januar' => 1, + 'februar' => 2, + 'märz' => 3, + 'april' => 4, + 'mai' => 5, + 'juni' => 6, + 'juli' => 7, + 'august' => 8, + 'september' => 9, + 'oktober' => 10, + 'november' => 11, + 'dezember' => 12, + // Italian + 'gennaio' => 1, + 'febbraio' => 2, + 'marzo' => 3, + 'aprile' => 4, + 'maggio' => 5, + 'giugno' => 6, + 'luglio' => 7, + 'agosto' => 8, + 'settembre' => 9, + 'ottobre' => 10, + 'novembre' => 11, + 'dicembre' => 12, + // Spanish + 'enero' => 1, + 'febrero' => 2, + 'marzo' => 3, + 'abril' => 4, + 'mayo' => 5, + 'junio' => 6, + 'julio' => 7, + 'agosto' => 8, + 'septiembre' => 9, + 'setiembre' => 9, + 'octubre' => 10, + 'noviembre' => 11, + 'diciembre' => 12, + // Finnish + 'tammikuu' => 1, + 'helmikuu' => 2, + 'maaliskuu' => 3, + 'huhtikuu' => 4, + 'toukokuu' => 5, + 'kesäkuu' => 6, + 'heinäkuu' => 7, + 'elokuu' => 8, + 'suuskuu' => 9, + 'lokakuu' => 10, + 'marras' => 11, + 'joulukuu' => 12, + // Hungarian + 'január' => 1, + 'február' => 2, + 'március' => 3, + 'április' => 4, + 'május' => 5, + 'június' => 6, + 'július' => 7, + 'augusztus' => 8, + 'szeptember' => 9, + 'október' => 10, + 'november' => 11, + 'december' => 12, + // Greek + 'Ιαν' => 1, + 'Φεβ' => 2, + 'Μάώ' => 3, + 'Μαώ' => 3, + 'Απρ' => 4, + 'Μάι' => 5, + 'Μαϊ' => 5, + 'Μαι' => 5, + 'Ιούν' => 6, + 'Ιον' => 6, + 'Ιούλ' => 7, + 'Ιολ' => 7, + 'Αύγ' => 8, + 'Αυγ' => 8, + 'Σεπ' => 9, + 'Οκτ' => 10, + 'Νοέ' => 11, + 'Δεκ' => 12, + ); - case 'CST': - $timezone = -21600; - break; + /** + * List of timezones, abbreviation => offset from UTC + * + * @access protected + * @var array + */ + var $timezone = array( + 'ACDT' => 37800, + 'ACIT' => 28800, + 'ACST' => 34200, + 'ACT' => -18000, + 'ACWDT' => 35100, + 'ACWST' => 31500, + 'AEDT' => 39600, + 'AEST' => 36000, + 'AFT' => 16200, + 'AKDT' => -28800, + 'AKST' => -32400, + 'AMDT' => 18000, + 'AMT' => -14400, + 'ANAST' => 46800, + 'ANAT' => 43200, + 'ART' => -10800, + 'AZOST' => -3600, + 'AZST' => 18000, + 'AZT' => 14400, + 'BIOT' => 21600, + 'BIT' => -43200, + 'BOT' => -14400, + 'BRST' => -7200, + 'BRT' => -10800, + 'BST' => 3600, + 'BTT' => 21600, + 'CAST' => 18000, + 'CAT' => 7200, + 'CCT' => 23400, + 'CDT' => -18000, + 'CEDT' => 7200, + 'CET' => 3600, + 'CGST' => -7200, + 'CGT' => -10800, + 'CHADT' => 49500, + 'CHAST' => 45900, + 'CIST' => -28800, + 'CKT' => -36000, + 'CLDT' => -10800, + 'CLST' => -14400, + 'COT' => -18000, + 'CST' => -21600, + 'CVT' => -3600, + 'CXT' => 25200, + 'DAVT' => 25200, + 'DTAT' => 36000, + 'EADT' => -18000, + 'EAST' => -21600, + 'EAT' => 10800, + 'ECT' => -18000, + 'EDT' => -14400, + 'EEST' => 10800, + 'EET' => 7200, + 'EGT' => -3600, + 'EKST' => 21600, + 'EST' => -18000, + 'FJT' => 43200, + 'FKDT' => -10800, + 'FKST' => -14400, + 'FNT' => -7200, + 'GALT' => -21600, + 'GEDT' => 14400, + 'GEST' => 10800, + 'GFT' => -10800, + 'GILT' => 43200, + 'GIT' => -32400, + 'GST' => 14400, + 'GST' => -7200, + 'GYT' => -14400, + 'HAA' => -10800, + 'HAC' => -18000, + 'HADT' => -32400, + 'HAE' => -14400, + 'HAP' => -25200, + 'HAR' => -21600, + 'HAST' => -36000, + 'HAT' => -9000, + 'HAY' => -28800, + 'HKST' => 28800, + 'HMT' => 18000, + 'HNA' => -14400, + 'HNC' => -21600, + 'HNE' => -18000, + 'HNP' => -28800, + 'HNR' => -25200, + 'HNT' => -12600, + 'HNY' => -32400, + 'IRDT' => 16200, + 'IRKST' => 32400, + 'IRKT' => 28800, + 'IRST' => 12600, + 'JFDT' => -10800, + 'JFST' => -14400, + 'JST' => 32400, + 'KGST' => 21600, + 'KGT' => 18000, + 'KOST' => 39600, + 'KOVST' => 28800, + 'KOVT' => 25200, + 'KRAST' => 28800, + 'KRAT' => 25200, + 'KST' => 32400, + 'LHDT' => 39600, + 'LHST' => 37800, + 'LINT' => 50400, + 'LKT' => 21600, + 'MAGST' => 43200, + 'MAGT' => 39600, + 'MAWT' => 21600, + 'MDT' => -21600, + 'MESZ' => 7200, + 'MEZ' => 3600, + 'MHT' => 43200, + 'MIT' => -34200, + 'MNST' => 32400, + 'MSDT' => 14400, + 'MSST' => 10800, + 'MST' => -25200, + 'MUT' => 14400, + 'MVT' => 18000, + 'MYT' => 28800, + 'NCT' => 39600, + 'NDT' => -9000, + 'NFT' => 41400, + 'NMIT' => 36000, + 'NOVST' => 25200, + 'NOVT' => 21600, + 'NPT' => 20700, + 'NRT' => 43200, + 'NST' => -12600, + 'NUT' => -39600, + 'NZDT' => 46800, + 'NZST' => 43200, + 'OMSST' => 25200, + 'OMST' => 21600, + 'PDT' => -25200, + 'PET' => -18000, + 'PETST' => 46800, + 'PETT' => 43200, + 'PGT' => 36000, + 'PHOT' => 46800, + 'PHT' => 28800, + 'PKT' => 18000, + 'PMDT' => -7200, + 'PMST' => -10800, + 'PONT' => 39600, + 'PST' => -28800, + 'PWT' => 32400, + 'PYST' => -10800, + 'PYT' => -14400, + 'RET' => 14400, + 'ROTT' => -10800, + 'SAMST' => 18000, + 'SAMT' => 14400, + 'SAST' => 7200, + 'SBT' => 39600, + 'SCDT' => 46800, + 'SCST' => 43200, + 'SCT' => 14400, + 'SEST' => 3600, + 'SGT' => 28800, + 'SIT' => 28800, + 'SRT' => -10800, + 'SST' => -39600, + 'SYST' => 10800, + 'SYT' => 7200, + 'TFT' => 18000, + 'THAT' => -36000, + 'TJT' => 18000, + 'TKT' => -36000, + 'TMT' => 18000, + 'TOT' => 46800, + 'TPT' => 32400, + 'TRUT' => 36000, + 'TVT' => 43200, + 'TWT' => 28800, + 'UYST' => -7200, + 'UYT' => -10800, + 'UZT' => 18000, + 'VET' => -14400, + 'VLAST' => 39600, + 'VLAT' => 36000, + 'VOST' => 21600, + 'VUT' => 39600, + 'WAST' => 7200, + 'WAT' => 3600, + 'WDT' => 32400, + 'WEST' => 3600, + 'WFT' => 43200, + 'WIB' => 25200, + 'WIT' => 32400, + 'WITA' => 28800, + 'WKST' => 18000, + 'WST' => 28800, + 'YAKST' => 36000, + 'YAKT' => 32400, + 'YAPT' => 36000, + 'YEKST' => 21600, + 'YEKT' => 18000, + ); - case 'MST': - $timezone = -25200; - break; + /** + * Cached PCRE for SimplePie_Parse_Date::$day + * + * @access protected + * @var string + */ + var $day_pcre; - case 'PST': - $timezone = -28800; - break; + /** + * Cached PCRE for SimplePie_Parse_Date::$month + * + * @access protected + * @var string + */ + var $month_pcre; - case 'EDT': - $timezone = -14400; - break; + /** + * Array of user-added callback methods + * + * @access private + * @var array + */ + var $built_in = array(); - case 'CDT': - $timezone = -18000; - break; + /** + * Array of user-added callback methods + * + * @access private + * @var array + */ + var $user = array(); - case 'MDT': - $timezone = -21600; - break; + /** + * Create new SimplePie_Parse_Date object, and set self::day_pcre, + * self::month_pcre, and self::built_in + * + * @access private + */ + function SimplePie_Parse_Date() + { + $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')'; + $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')'; - case 'PDT': - $timezone = -25200; - break; - } - } - } - // Timezone difference from UTC - else - { - $timezone = 0; - $timezone += ($match[24] + ('.' . $match[25])) * 3600; - $timezone += ($match[26] + ('.' . $match[27])) * 60; - $timezone = (int) round($timezone); + static $cache; + if (!isset($cache[get_class($this)])) + { + $all_methods = get_class_methods($this); - if ($match[23] == '-') - { - $timezone = -$timezone; - } - } - } - } - if ($timezone === false) - { - $cache[$dt][$rfc822_tz] = mktime($hour, $minute, $second, $month, $day, $year); - } - else + foreach ($all_methods as $method) + { + if (strtolower(substr($method, 0, 5)) === 'date_') { - $cache[$dt][$rfc822_tz] = gmmktime($hour, $minute, $second, $month, $day, $year) - $timezone; + $cache[get_class($this)][] = $method; } } - elseif (($time = strtotime($dt)) > 0) - { - $cache[$dt][$rfc822_tz] = $time; - } - else - { - $cache[$dt][$rfc822_tz] = false; - } } - return $cache[$dt][$rfc822_tz]; + + foreach ($cache[get_class($this)] as $method) + { + $this->built_in[] = $method; + } } /** - * Decode HTML entities + * Get the object * - * @static * @access public - * @param string $data Input data - * @return string Output data */ - function entities_decode($data) + function get() { - $decoder = new SimplePie_Decode_HTML_Entities($data); - return $decoder->parse(); + static $object; + if (!$object) + { + $object = new SimplePie_Parse_Date; + } + return $object; } /** - * Remove RFC822 comments + * Parse a date * - * @author Tomas V.V.Cox - * @author Pierre-Alain Joye - * @author Amir Mohammad Saied - * @copyright 1997-2006 Pierre-Alain Joye,Tomas V.V.Cox,Amir Mohammad Saied - * @license http://www.opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Validate.php,v 1.104 2006/11/17 16:32:06 amir Exp $ - * @link http://pear.php.net/package/Validate + * @final * @access public - * @param string $data Data to strip comments from - * @return string Comment stripped string + * @param string $date Date to parse + * @return int Timestamp corresponding to date string, or false on failure */ - function uncomment_rfc822($data) - { - if ((version_compare(PHP_VERSION, '4.4.6', '>=') && version_compare(PHP_VERSION, '5', '<')) || version_compare(PHP_VERSION, '5.2.2', '>=')) - { - return $data; - } - else - { - return preg_replace('/((?:(?:\\\\"|[^("])*(?:"(?:[^"\\\\\r]|\\\\.)*"\s*)?)*)((?user as $method) { - return trim($mime); + if (($returned = call_user_func($method, $date)) !== false) + { + return $returned; + } } - else + + foreach ($this->built_in as $method) { - return trim(substr($mime, 0, $pos)); + if (($returned = call_user_func(array(&$this, $method), $date)) !== false) + { + return $returned; + } } + + return false; } - function htmlspecialchars_decode($string, $quote_style) + /** + * Add a callback method to parse a date + * + * @final + * @access public + * @param callback $callback + */ + function add_callback($callback) { - if (function_exists('htmlspecialchars_decode')) + if (is_callable($callback)) { - return htmlspecialchars_decode($string, $quote_style); + $this->user[] = $callback; } else { - return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style))); + trigger_error('User-supplied function must be a valid callback', E_USER_WARNING); } } - function atom_03_construct_type($attribs) + /** + * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as + * well as allowing any of upper or lower case "T", horizontal tabs, or + * spaces to be used as the time seperator (including more than one)) + * + * @access protected + * @return int Timestamp + */ + function date_w3cdtf($date) { - if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) == 'base64')) - { - $mode = SIMPLEPIE_CONSTRUCT_BASE64; - } - else + static $pcre; + if (!$pcre) { - $mode = SIMPLEPIE_CONSTRUCT_NONE; + $year = '([0-9]{4})'; + $month = $day = $hour = $minute = $second = '([0-9]{2})'; + $decimal = '([0-9]*)'; + $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))'; + $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/'; } - if (isset($attribs['']['type'])) + if (preg_match($pcre, $date, $match)) { - switch (strtolower(trim($attribs['']['type']))) - { - case 'text': - case 'text/plain': - return SIMPLEPIE_CONSTRUCT_TEXT | $mode; + /* + Capturing subpatterns: + 1: Year + 2: Month + 3: Day + 4: Hour + 5: Minute + 6: Second + 7: Decimal fraction of a second + 8: Zulu + 9: Timezone ± + 10: Timezone hours + 11: Timezone minutes + */ - case 'html': - case 'text/html': - return SIMPLEPIE_CONSTRUCT_HTML | $mode; + // Fill in empty matches + for ($i = count($match); $i <= 3; $i++) + { + $match[$i] = '1'; + } - case 'xhtml': - case 'application/xhtml+xml': - return SIMPLEPIE_CONSTRUCT_XHTML | $mode; + for ($i = count($match); $i <= 7; $i++) + { + $match[$i] = '0'; + } - default: - return SIMPLEPIE_CONSTRUCT_NONE | $mode; + // Numeric timezone + if (isset($match[9]) && $match[9] !== '') + { + $timezone = $match[10] * 3600; + $timezone += $match[11] * 60; + if ($match[9] === '-') + { + $timezone = 0 - $timezone; + } + } + else + { + $timezone = 0; } + + // Convert the number of seconds to an integer, taking decimals into account + $second = round($match[6] + $match[7] / pow(10, strlen($match[7]))); + + return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone; } else { - return SIMPLEPIE_CONSTRUCT_TEXT | $mode; + return false; } } - function atom_10_construct_type($attribs) + /** + * Remove RFC822 comments + * + * @access protected + * @param string $data Data to strip comments from + * @return string Comment stripped string + */ + function remove_rfc2822_comments($string) { - if (isset($attribs['']['type'])) - { - switch (strtolower(trim($attribs['']['type']))) - { - case 'text': - return SIMPLEPIE_CONSTRUCT_TEXT; + $string = (string) $string; + $position = 0; + $length = strlen($string); + $depth = 0; - case 'html': - return SIMPLEPIE_CONSTRUCT_HTML; + $output = ''; - case 'xhtml': - return SIMPLEPIE_CONSTRUCT_XHTML; + while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) + { + $output .= substr($string, $position, $pos - $position); + $position = $pos + 1; + if ($string[$pos - 1] !== '\\') + { + $depth++; + while ($depth && $position < $length) + { + $position += strcspn($string, '()', $position); + if ($string[$position - 1] === '\\') + { + $position++; + continue; + } + elseif (isset($string[$position])) + { + switch ($string[$position]) + { + case '(': + $depth++; + break; - default: - return SIMPLEPIE_CONSTRUCT_NONE; + case ')': + $depth--; + break; + } + $position++; + } + else + { + break; + } + } + } + else + { + $output .= '('; } } - return SIMPLEPIE_CONSTRUCT_TEXT; + $output .= substr($string, $position); + + return $output; } - function atom_10_content_construct_type($attribs) + /** + * Parse RFC2822's date format + * + * @access protected + * @return int Timestamp + */ + function date_rfc2822($date) { - if (isset($attribs['']['type'])) + static $pcre; + if (!$pcre) { - $type = strtolower(trim($attribs['']['type'])); - switch ($type) - { - case 'text': - return SIMPLEPIE_CONSTRUCT_TEXT; + $wsp = '[\x09\x20]'; + $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)'; + $optional_fws = $fws . '?'; + $day_name = $this->day_pcre; + $month = $this->month_pcre; + $day = '([0-9]{1,2})'; + $hour = $minute = $second = '([0-9]{2})'; + $year = '([0-9]{2,4})'; + $num_zone = '([+\-])([0-9]{2})([0-9]{2})'; + $character_zone = '([A-Z]{1,5})'; + $zone = '(?:' . $num_zone . '|' . $character_zone . ')'; + $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'; + } + if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match)) + { + /* + Capturing subpatterns: + 1: Day name + 2: Day + 3: Month + 4: Year + 5: Hour + 6: Minute + 7: Second + 8: Timezone ± + 9: Timezone hours + 10: Timezone minutes + 11: Alphabetic timezone + */ - case 'html': - return SIMPLEPIE_CONSTRUCT_HTML; + // Find the month number + $month = $this->month[strtolower($match[3])]; - case 'xhtml': - return SIMPLEPIE_CONSTRUCT_XHTML; + // Numeric timezone + if ($match[8] !== '') + { + $timezone = $match[9] * 3600; + $timezone += $match[10] * 60; + if ($match[8] === '-') + { + $timezone = 0 - $timezone; + } } - if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) == 'text/') + // Character timezone + elseif (isset($this->timezone[strtoupper($match[11])])) { - return SIMPLEPIE_CONSTRUCT_NONE; + $timezone = $this->timezone[strtoupper($match[11])]; } + // Assume everything else to be -0000 else { - return SIMPLEPIE_CONSTRUCT_BASE64; + $timezone = 0; + } + + // Deal with 2/3 digit years + if ($match[4] < 50) + { + $match[4] += 2000; + } + elseif ($match[4] < 1000) + { + $match[4] += 1900; + } + + // Second is optional, if it is empty set it to zero + if ($match[7] !== '') + { + $second = $match[7]; + } + else + { + $second = 0; } + + return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone; } else { - return SIMPLEPIE_CONSTRUCT_TEXT; + return false; } } - function is_isegment_nz_nc($string) + /** + * Parse RFC850's date format + * + * @access protected + * @return int Timestamp + */ + function date_rfc850($date) { - 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); - } + static $pcre; + if (!$pcre) + { + $space = '[\x09\x20]+'; + $day_name = $this->day_pcre; + $month = $this->month_pcre; + $day = '([0-9]{1,2})'; + $year = $hour = $minute = $second = '([0-9]{2})'; + $zone = '([A-Z]{1,5})'; + $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i'; + } + if (preg_match($pcre, $date, $match)) + { + /* + Capturing subpatterns: + 1: Day name + 2: Day + 3: Month + 4: Year + 5: Hour + 6: Minute + 7: Second + 8: Timezone + */ - function space_seperated_tokens($string) - { - $space_characters = "\x20\x09\x0A\x0B\x0C\x0D"; - $string_length = strlen($string); + // Month + $month = $this->month[strtolower($match[3])]; - $position = strspn($string, $space_characters); - $tokens = array(); + // Character timezone + if (isset($this->timezone[strtoupper($match[8])])) + { + $timezone = $this->timezone[strtoupper($match[8])]; + } + // Assume everything else to be -0000 + else + { + $timezone = 0; + } - while ($position < $string_length) + // Deal with 2 digit year + if ($match[4] < 50) + { + $match[4] += 2000; + } + else + { + $match[4] += 1900; + } + + return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone; + } + else { - $len = strcspn($string, $space_characters, $position); - $tokens[] = substr($string, $position, $len); - $position += $len; - $position += strspn($string, $space_characters, $position); + return false; } + } - return $tokens; + /** + * Parse C99's asctime()'s date format + * + * @access protected + * @return int Timestamp + */ + function date_asctime($date) + { + static $pcre; + if (!$pcre) + { + $space = '[\x09\x20]+'; + $wday_name = $this->day_pcre; + $mon_name = $this->month_pcre; + $day = '([0-9]{1,2})'; + $hour = $sec = $min = '([0-9]{2})'; + $year = '([0-9]{4})'; + $terminator = '\x0A?\x00?'; + $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i'; + } + if (preg_match($pcre, $date, $match)) + { + /* + Capturing subpatterns: + 1: Day name + 2: Month + 3: Day + 4: Hour + 5: Minute + 6: Second + 7: Year + */ + + $month = $this->month[strtolower($match[2])]; + return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]); + } + else + { + return false; + } } - function array_unique($array) + /** + * Parse dates using strtotime() + * + * @access protected + * @return int Timestamp + */ + function date_strtotime($date) { - if (version_compare(PHP_VERSION, '5.2', '>=')) + $strtotime = strtotime($date); + if ($strtotime === -1 || $strtotime === false) { - return array_unique($array); + return false; } else { - $array = (array) $array; - $new_array = array(); - $new_array_strings = array(); - foreach ($array as $key => $value) + return $strtotime; + } + } +} + +/** + * Content-type sniffing + * + * @package SimplePie + */ +class SimplePie_Content_Type_Sniffer +{ + /** + * File object + * + * @var SimplePie_File + * @access private + */ + var $file; + + /** + * Create an instance of the class with the input file + * + * @access public + * @param SimplePie_Content_Type_Sniffer $file Input file + */ + function SimplePie_Content_Type_Sniffer($file) + { + $this->file = $file; + } + + /** + * Get the Content-Type of the specified file + * + * @access public + * @return string Actual Content-Type + */ + function get_type() + { + if (isset($this->file->headers['content-type'])) + { + if (!isset($this->file->headers['content-encoding']) + && ($this->file->headers['content-type'] === 'text/plain' + || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1' + || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1')) { - if (is_object($value)) - { - if (method_exists($value, '__toString')) - { - $cmp = $value->__toString(); - } - else - { - trigger_error('Object of class ' . get_class($value) . ' could not be converted to string', E_USER_ERROR); - } - } - elseif (is_array($value)) + return $this->text_or_binary(); + } + + if (($pos = strpos($this->file->headers['content-type'], ';')) !== false) + { + $official = substr($this->file->headers['content-type'], 0, $pos); + } + else + { + $official = $this->file->headers['content-type']; + } + $official = strtolower($official); + + if ($official === 'unknown/unknown' + || $official === 'application/unknown') + { + return $this->unknown(); + } + elseif (substr($official, -4) === '+xml' + || $official === 'text/xml' + || $official === 'application/xml') + { + return $official; + } + elseif (substr($official, 0, 6) === 'image/') + { + if ($return = $this->image()) { - $cmp = (string) reset($value); + return $return; } else { - $cmp = (string) $value; - } - if (!in_array($cmp, $new_array_strings)) - { - $new_array[$key] = $value; - $new_array_strings[] = $cmp; + return $official; } } - return $new_array; + elseif ($official === 'text/html') + { + return $this->feed_or_html(); + } + else + { + return $official; + } + } + else + { + return $this->unknown(); } } /** - * Converts a unicode codepoint to a UTF-8 character + * Sniff text or binary * - * @static - * @access public - * @param int $codepoint Unicode codepoint - * @return string UTF-8 character + * @access private + * @return string Actual Content-Type */ - function codepoint_to_utf8($codepoint) + function text_or_binary() { - static $cache = array(); - $codepoint = (int) $codepoint; - if (isset($cache[$codepoint])) + if (substr($this->file->body, 0, 2) === "\xFE\xFF" + || substr($this->file->body, 0, 2) === "\xFF\xFE" + || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF" + || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF") { - return $cache[$codepoint]; + return 'text/plain'; } - elseif ($codepoint < 0) + elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body)) { - return $cache[$codepoint] = false; + return 'application/octect-stream'; } - else if ($codepoint <= 0x7f) + else { - return $cache[$codepoint] = chr($codepoint); + return 'text/plain'; } - else if ($codepoint <= 0x7ff) + } + + /** + * Sniff unknown + * + * @access private + * @return string Actual Content-Type + */ + function unknown() + { + $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20"); + if (strtolower(substr($this->file->body, $ws, 14)) === 'file->body, $ws, 5)) === 'file->body, $ws, 7)) === '> 6)) . chr(0x80 | ($codepoint & 0x3f)); + return 'text/html'; } - else if ($codepoint <= 0xffff) + elseif (substr($this->file->body, 0, 5) === '%PDF-') { - return $cache[$codepoint] = chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); + return 'application/pdf'; } - else if ($codepoint <= 0x10ffff) + elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-') + { + return 'application/postscript'; + } + elseif (substr($this->file->body, 0, 6) === 'GIF87a' + || substr($this->file->body, 0, 6) === 'GIF89a') + { + return 'image/gif'; + } + elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") + { + return 'image/png'; + } + elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") + { + return 'image/jpeg'; + } + elseif (substr($this->file->body, 0, 2) === "\x42\x4D") { - return $cache[$codepoint] = chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); + return 'image/bmp'; } else { - // U+FFFD REPLACEMENT CHARACTER - return $cache[$codepoint] = "\xEF\xBF\xBD"; + return $this->text_or_binary(); } } /** - * Re-implementation of PHP 4.2.0's is_a() + * Sniff images * - * @static - * @access public - * @param object $object The tested object - * @param string $class_name The class name - * @return bool Returns true if the object is of this class or has this class as one of its parents, false otherwise - */ - function is_a($object, $class_name) - { - if (function_exists('is_a')) - { - return is_a($object, $class_name); - } - elseif (!is_object($object)) - { - return false; - } - elseif (get_class($object) == strtolower($class_name)) - { - return true; - } - else - { - return is_subclass_of($object, $class_name); - } - } + * @access private + * @return string Actual Content-Type + */ + function image() + { + if (substr($this->file->body, 0, 6) === 'GIF87a' + || substr($this->file->body, 0, 6) === 'GIF89a') + { + return 'image/gif'; + } + elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") + { + return 'image/png'; + } + elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") + { + return 'image/jpeg'; + } + elseif (substr($this->file->body, 0, 2) === "\x42\x4D") + { + return 'image/bmp'; + } + else + { + return false; + } + } /** - * Re-implementation of PHP 5's stripos() - * - * Returns the numeric position of the first occurrence of needle in the - * haystack string. + * Sniff HTML * - * @static - * @access string - * @param object $haystack - * @param string $needle Note that the needle may be a string of one or more - * characters. If needle is not a string, it is converted to an integer - * and applied as the ordinal value of a character. - * @param int $offset The optional offset parameter allows you to specify which - * character in haystack to start searching. The position returned is still - * relative to the beginning of haystack. - * @return bool If needle is not found, stripos() will return boolean false. + * @access private + * @return string Actual Content-Type */ - function stripos($haystack, $needle, $offset = 0) - { - if (function_exists('stripos')) - { - return stripos($haystack, $needle, $offset); - } - else - { - if (is_string($needle)) - { - $needle = strtolower($needle); - } - elseif (is_int($needle) || is_bool($needle) || is_double($needle)) - { - $needle = strtolower(chr($needle)); - } - else - { - trigger_error('needle is not a string or an integer', E_USER_WARNING); - return false; - } - - return strpos(strtolower($haystack), $needle, $offset); - } - } + function feed_or_html() + { + $len = strlen($this->file->body); + $pos = strspn($this->file->body, "\x09\x0A\x0D\x20"); + + while ($pos < $len) + { + switch ($this->file->body[$pos]) + { + case "\x09": + case "\x0A": + case "\x0D": + case "\x20": + $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos); + continue 2; + + case '<': + $pos++; + break; + + default: + return 'text/html'; + } + + if (substr($this->file->body, $pos, 3) === '!--') + { + $pos += 3; + if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false) + { + $pos += 3; + } + else + { + return 'text/html'; + } + } + elseif (substr($this->file->body, $pos, 1) === '!') + { + if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false) + { + $pos++; + } + else + { + return 'text/html'; + } + } + elseif (substr($this->file->body, $pos, 1) === '?') + { + if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false) + { + $pos += 2; + } + else + { + return 'text/html'; + } + } + elseif (substr($this->file->body, $pos, 3) === 'rss' + || substr($this->file->body, $pos, 7) === 'rdf:RDF') + { + return 'application/rss+xml'; + } + elseif (substr($this->file->body, $pos, 4) === 'feed') + { + return 'application/atom+xml'; + } + else + { + return 'text/html'; + } + } + + return 'text/html'; + } } /** - * Decode HTML Entities - * - * This implements HTML5 as of revision 967 (2007-06-28) + * Parses the XML Declaration * * @package SimplePie */ -class SimplePie_Decode_HTML_Entities +class SimplePie_XML_Declaration_Parser { /** - * Data to be parsed + * XML Version + * + * @access public + * @var string + */ + var $version = '1.0'; + + /** + * Encoding + * + * @access public + * @var string + */ + var $encoding = 'UTF-8'; + + /** + * Standalone + * + * @access public + * @var bool + */ + var $standalone = false; + + /** + * Current state of the state machine * * @access private * @var string */ - var $data = ''; + var $state = 'before_version_name'; /** - * Currently consumed bytes + * Input data * * @access private * @var string */ - var $consumed = ''; + var $data = ''; /** - * Position of the current byte being parsed + * Input data length (to avoid calling strlen() everytime this is needed) * * @access private * @var int */ + var $data_length = 0; + + /** + * Current position of the pointer + * + * @var int + * @access private + */ var $position = 0; /** @@ -9824,169 +13822,250 @@ class SimplePie_Decode_HTML_Entities * @access public * @param string $data Input data */ - function SimplePie_Decode_HTML_Entities($data) + function SimplePie_XML_Declaration_Parser($data) { $this->data = $data; + $this->data_length = strlen($this->data); } /** * Parse the input data * * @access public - * @return string Output data + * @return bool true on success, false on failure */ function parse() { - while (($this->position = strpos($this->data, '&', $this->position)) !== false) + while ($this->state && $this->state !== 'emit' && $this->has_data()) + { + $state = $this->state; + $this->$state(); + } + $this->data = ''; + if ($this->state === 'emit') + { + return true; + } + else + { + $this->version = ''; + $this->encoding = ''; + $this->standalone = ''; + return false; + } + } + + /** + * Check whether there is data beyond the pointer + * + * @access private + * @return bool true if there is further data, false if not + */ + function has_data() + { + return (bool) ($this->position < $this->data_length); + } + + /** + * Advance past any whitespace + * + * @return int Number of whitespace characters passed + */ + function skip_whitespace() + { + $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position); + $this->position += $whitespace; + return $whitespace; + } + + /** + * Read value + */ + function get_value() + { + $quote = substr($this->data, $this->position, 1); + if ($quote === '"' || $quote === "'") + { + $this->position++; + $len = strcspn($this->data, $quote, $this->position); + if ($this->has_data()) + { + $value = substr($this->data, $this->position, $len); + $this->position += $len + 1; + return $value; + } + } + return false; + } + + function before_version_name() + { + if ($this->skip_whitespace()) + { + $this->state = 'version_name'; + } + else + { + $this->state = false; + } + } + + function version_name() + { + if (substr($this->data, $this->position, 7) === 'version') + { + $this->position += 7; + $this->skip_whitespace(); + $this->state = 'version_equals'; + } + else + { + $this->state = false; + } + } + + function version_equals() + { + if (substr($this->data, $this->position, 1) === '=') + { + $this->position++; + $this->skip_whitespace(); + $this->state = 'version_value'; + } + else + { + $this->state = false; + } + } + + function version_value() + { + if ($this->version = $this->get_value()) + { + $this->skip_whitespace(); + if ($this->has_data()) + { + $this->state = 'encoding_name'; + } + else + { + $this->state = 'emit'; + } + } + else + { + $this->state = false; + } + } + + function encoding_name() + { + if (substr($this->data, $this->position, 8) === 'encoding') + { + $this->position += 8; + $this->skip_whitespace(); + $this->state = 'encoding_equals'; + } + else + { + $this->state = 'standalone_name'; + } + } + + function encoding_equals() + { + if (substr($this->data, $this->position, 1) === '=') { - $this->consume(); - $this->entity(); - $this->consumed = ''; + $this->position++; + $this->skip_whitespace(); + $this->state = 'encoding_value'; + } + else + { + $this->state = false; } - return $this->data; } - /** - * Consume the next byte - * - * @access private - * @return mixed The next byte, or false, if there is no more data - */ - function consume() + function encoding_value() { - if (isset($this->data[$this->position])) + if ($this->encoding = $this->get_value()) { - $this->consumed .= $this->data[$this->position]; - return $this->data[$this->position++]; + $this->skip_whitespace(); + if ($this->has_data()) + { + $this->state = 'standalone_name'; + } + else + { + $this->state = 'emit'; + } } else { - $this->consumed = false; - return false; + $this->state = false; } } - /** - * Consume a range of characters - * - * @access private - * @param string $chars Characters to consume - * @return mixed A series of characters that match the range, or false - */ - function consume_range($chars) + function standalone_name() { - if ($len = strspn($this->data, $chars, $this->position)) + if (substr($this->data, $this->position, 10) === 'standalone') { - $data = substr($this->data, $this->position, $len); - $this->consumed .= $data; - $this->position += $len; - return $data; + $this->position += 10; + $this->skip_whitespace(); + $this->state = 'standalone_equals'; } else { - $this->consumed = false; - return false; + $this->state = false; } } - /** - * Unconsume one byte - * - * @access private - */ - function unconsume() + function standalone_equals() { - $this->consumed = substr($this->consumed, 0, -1); - $this->position--; + if (substr($this->data, $this->position, 1) === '=') + { + $this->position++; + $this->skip_whitespace(); + $this->state = 'standalone_value'; + } + else + { + $this->state = false; + } } - /** - * Decode an entity - * - * @access private - */ - function entity() + function standalone_value() { - switch ($this->consume()) + if ($standalone = $this->get_value()) { - case "\x09": - case "\x0A": - case "\x0B": - case "\x0B": - case "\x0C": - case "\x20": - case "\x3C": - case "\x26": - case false: - break; - - case "\x23": - switch ($this->consume()) - { - case "\x78": - case "\x58": - $range = '0123456789ABCDEFabcdef'; - $hex = true; - break; - - default: - $range = '0123456789'; - $hex = false; - $this->unconsume(); - break; - } - - if ($codepoint = $this->consume_range($range)) - { - 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"); - - if ($hex) - { - $codepoint = hexdec($codepoint); - } - else - { - $codepoint = intval($codepoint); - } - - if (isset($windows_1252_specials[$codepoint])) - { - $replacement = $windows_1252_specials[$codepoint]; - } - else - { - $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint); - } - - if ($this->consume() != ';') - { - $this->unconsume(); - } - - $consumed_length = strlen($this->consumed); - $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length); - $this->position += strlen($replacement) - $consumed_length; - } - break; + switch ($standalone) + { + case 'yes': + $this->standalone = true; + break; - default: - 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"); + case 'no': + $this->standalone = false; + break; - for ($i = 0, $match = null; $i < 9 && $this->consume(); $i++) - { - $consumed = substr($this->consumed, 1); - if (isset($entities[$consumed])) - { - $match = $consumed; - } - } + default: + $this->state = false; + return; + } - if ($match !== null) - { - $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1); - $this->position += strlen($entities[$match]) - strlen($consumed) - 1; - } - break; + $this->skip_whitespace(); + if ($this->has_data()) + { + $this->state = false; + } + else + { + $this->state = 'emit'; + } + } + else + { + $this->state = false; } } } @@ -10005,23 +14084,34 @@ class SimplePie_Locator var $base_location = 0; var $checked_feeds = 0; var $max_checked_feeds = 10; + var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer'; - function SimplePie_Locator(&$file, $timeout = 10, $useragent = null, $file_class = 'SimplePie_File', $max_checked_feeds = 10) + function SimplePie_Locator(&$file, $timeout = 10, $useragent = null, $file_class = 'SimplePie_File', $max_checked_feeds = 10, $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer') { $this->file =& $file; $this->file_class = $file_class; $this->useragent = $useragent; $this->timeout = $timeout; $this->max_checked_feeds = $max_checked_feeds; + $this->content_type_sniffer_class = $content_type_sniffer_class; } - function find($type = SIMPLEPIE_LOCATOR_ALL) + function find($type = SIMPLEPIE_LOCATOR_ALL, &$working) { if ($this->is_feed($this->file)) { return $this->file; } + if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) + { + $sniffer = new $this->content_type_sniffer_class($this->file); + if ($sniffer->get_type() !== 'text/html') + { + return null; + } + } + if ($type & ~SIMPLEPIE_LOCATOR_NONE) { $this->get_base(); @@ -10029,7 +14119,7 @@ class SimplePie_Locator if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery()) { - return $working; + return $working[0]; } if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links()) @@ -10059,24 +14149,32 @@ class SimplePie_Locator function is_feed(&$file) { - $body = SimplePie_Misc::strip_comments($file->body); - if (preg_match('/<([^\s:]+:)?(rss|RDF|feed)' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/i', $body)) + if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) { - return true; + $sniffer = new $this->content_type_sniffer_class($file); + $sniffed = $sniffer->get_type(); + if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml'))) + { + return true; + } + else + { + return false; + } } - return false; - } - - function get_base() - { - if (isset($this->file->headers['content-location'])) + elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL) { - $this->http_base = SimplePie_Misc::absolutize_url(trim($this->file->headers['content-location']), $this->file->url); + return true; } else { - $this->http_base = $this->file->url; + return false; } + } + + function get_base() + { + $this->http_base = $this->file->url; $this->base = $this->http_base; $elements = SimplePie_Misc::get_element('base', $this->file->body); foreach ($elements as $element) @@ -10094,9 +14192,10 @@ class SimplePie_Locator { $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)); $done = array(); + $feeds = array(); foreach ($links as $link) { - if ($this->checked_feeds == $this->max_checked_feeds) + if ($this->checked_feeds === $this->max_checked_feeds) { break; } @@ -10113,19 +14212,26 @@ class SimplePie_Locator $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base); } - 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')))) + 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])) { $this->checked_feeds++; $feed = new $this->file_class($href, $this->timeout, 5, null, $this->useragent); - if ($this->is_feed($feed)) + 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)) { - return $feed; + $feeds[$href] = $feed; } } $done[] = $href; } } - return null; + + if (!empty($feeds)) + { + return array_values($feeds); + } + else { + return null; + } } function get_links() @@ -10150,7 +14256,7 @@ class SimplePie_Locator $current = SimplePie_Misc::parse_url($this->file->url); - if ($parsed['authority'] === '' || $parsed['authority'] == $current['authority']) + if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority']) { $this->local[] = $href; } @@ -10174,7 +14280,7 @@ class SimplePie_Locator { foreach ($array as $key => $value) { - if ($this->checked_feeds == $this->max_checked_feeds) + if ($this->checked_feeds === $this->max_checked_feeds) { break; } @@ -10182,7 +14288,7 @@ class SimplePie_Locator { $this->checked_feeds++; $feed = new $this->file_class($value, $this->timeout, 5, null, $this->useragent); - if ($this->is_feed($feed)) + 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)) { return $feed; } @@ -10199,7 +14305,7 @@ class SimplePie_Locator { foreach ($array as $key => $value) { - if ($this->checked_feeds == $this->max_checked_feeds) + if ($this->checked_feeds === $this->max_checked_feeds) { break; } @@ -10207,7 +14313,7 @@ class SimplePie_Locator { $this->checked_feeds++; $feed = new $this->file_class($value, $this->timeout, 5, null, $this->useragent); - if ($this->is_feed($feed)) + 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)) { return $feed; } @@ -10223,14 +14329,12 @@ class SimplePie_Locator class SimplePie_Parser { - var $xml; var $error_code; var $error_string; var $current_line; var $current_column; var $current_byte; var $separator = ' '; - var $feed = false; var $namespace = array(''); var $element = array(''); var $xml_base = array(''); @@ -10241,10 +14345,10 @@ class SimplePie_Parser var $current_xhtml_construct = -1; var $encoding; - function pre_process(&$data, $encoding) + function parse(&$data, $encoding) { // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character - if (strtoupper($encoding) == 'US-ASCII') + if (strtoupper($encoding) === 'US-ASCII') { $this->encoding = 'UTF-8'; } @@ -10255,68 +14359,150 @@ class SimplePie_Parser // Strip BOM: // UTF-32 Big Endian BOM - if (strpos($data, "\x0\x0\xFE\xFF") === 0) + if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") { $data = substr($data, 4); } // UTF-32 Little Endian BOM - elseif (strpos($data, "\xFF\xFE\x0\x0") === 0) + elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") { $data = substr($data, 4); } // UTF-16 Big Endian BOM - elseif (strpos($data, "\xFE\xFF") === 0) + elseif (substr($data, 0, 2) === "\xFE\xFF") { $data = substr($data, 2); } // UTF-16 Little Endian BOM - elseif (strpos($data, "\xFF\xFE") === 0) + elseif (substr($data, 0, 2) === "\xFF\xFE") { $data = substr($data, 2); } // UTF-8 BOM - elseif (strpos($data, "\xEF\xBB\xBF") === 0) + elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") { $data = substr($data, 3); } - // Make sure the XML prolog is sane and has the correct encoding - $data = preg_replace("/^<\?xml[\x20\x9\xD\xA]+version([\x20\x9\xD\xA]+)?=([\x20\x9\xD\xA]+)?(\"1.0\"|'1.0'|\"1.1\"|'1.1')([\x20\x9\xD\xA]+encoding([\x20\x9\xD\xA]+)?=([\x20\x9\xD\xA]+)?(\"[A-Za-z][A-Za-z0-9._\-]*\"|'[A-Za-z][A-Za-z0-9._\-]*'))?([\x20\x9\xD\xA]+standalone([\x20\x9\xD\xA]+)?=([\x20\x9\xD\xA]+)?(\"(yes|no)\"|'(yes|no)'))?([\x20\x9\xD\xA]+)?\?>/", '', $data); - $data = "\n" . $data; - } + if (substr($data, 0, 5) === '')) !== false) + { + $declaration = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5)); + if ($declaration->parse()) + { + $data = substr($data, $pos + 2); + $data = 'version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data; + } + else + { + $this->error_string = 'SimplePie bug! Please report this!'; + return false; + } + } - function parse(&$data) - { $return = true; + static $xml_is_sane = null; + if ($xml_is_sane === null) + { + $parser_check = xml_parser_create(); + xml_parse_into_struct($parser_check, '&', $values); + xml_parser_free($parser_check); + $xml_is_sane = isset($values[0]['value']); + } + // Create the parser - $this->xml = xml_parser_create_ns($this->encoding, $this->separator); - xml_parser_set_option($this->xml, XML_OPTION_SKIP_WHITE, 1); - xml_parser_set_option($this->xml, XML_OPTION_CASE_FOLDING, 0); - xml_set_object($this->xml, $this); - xml_set_character_data_handler($this->xml, 'cdata'); - xml_set_element_handler($this->xml, 'tag_open', 'tag_close'); - - // workound for a bug in PHP/libxml2 as described on http://bugs.simplepie.org/issues/show/101 - $data = str_replace('<', '<', $data); - $data = str_replace('>', '>', $data); - $data = str_replace('&', '&', $data); - $data = str_replace(''', ''', $data); - $data = str_replace('"', '"', $data); - - // Parse! - if (!xml_parse($this->xml, $data, true)) - { - $this->data = null; - $this->error_code = xml_get_error_code($this->xml); - $this->error_string = xml_error_string($this->error_code); - $return = false; - } - $this->current_line = xml_get_current_line_number($this->xml); - $this->current_column = xml_get_current_column_number($this->xml); - $this->current_byte = xml_get_current_byte_index($this->xml); - xml_parser_free($this->xml); - return $return; + if ($xml_is_sane) + { + $xml = xml_parser_create_ns($this->encoding, $this->separator); + xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0); + xml_set_object($xml, $this); + xml_set_character_data_handler($xml, 'cdata'); + xml_set_element_handler($xml, 'tag_open', 'tag_close'); + + // Parse! + if (!xml_parse($xml, $data, true)) + { + $this->error_code = xml_get_error_code($xml); + $this->error_string = xml_error_string($this->error_code); + $return = false; + } + $this->current_line = xml_get_current_line_number($xml); + $this->current_column = xml_get_current_column_number($xml); + $this->current_byte = xml_get_current_byte_index($xml); + xml_parser_free($xml); + return $return; + } + else + { + libxml_clear_errors(); + $xml = new XMLReader(); + $xml->xml($data); + while (@$xml->read()) + { + switch ($xml->nodeType) + { + + case constant('XMLReader::END_ELEMENT'): + if ($xml->namespaceURI !== '') + { + $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}"; + } + else + { + $tagName = $xml->localName; + } + $this->tag_close(null, $tagName); + break; + case constant('XMLReader::ELEMENT'): + $empty = $xml->isEmptyElement; + if ($xml->namespaceURI !== '') + { + $tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}"; + } + else + { + $tagName = $xml->localName; + } + $attributes = array(); + while ($xml->moveToNextAttribute()) + { + if ($xml->namespaceURI !== '') + { + $attrName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}"; + } + else + { + $attrName = $xml->localName; + } + $attributes[$attrName] = $xml->value; + } + $this->tag_open(null, $tagName, $attributes); + if ($empty) + { + $this->tag_close(null, $tagName); + } + break; + case constant('XMLReader::TEXT'): + + case constant('XMLReader::CDATA'): + $this->cdata(null, $xml->value); + break; + } + } + if ($error = libxml_get_last_error()) + { + $this->error_code = $error->code; + $this->error_string = $error->message; + $this->current_line = $error->line; + $this->current_column = $error->column; + return false; + } + else + { + return true; + } + } } function get_error_code() @@ -10351,27 +14537,6 @@ class SimplePie_Parser function tag_open($parser, $tag, $attributes) { - if ($this->feed === 0) - { - return; - } - elseif ($this->feed == false) - { - if (in_array($tag, array( - SIMPLEPIE_NAMESPACE_ATOM_10 . $this->separator . 'feed', - SIMPLEPIE_NAMESPACE_ATOM_03 . $this->separator . 'feed', - 'rss', - SIMPLEPIE_NAMESPACE_RDF . $this->separator . 'RDF' - ))) - { - $this->feed = 1; - } - } - else - { - $this->feed++; - } - list($this->namespace[], $this->element[]) = $this->split_ns($tag); $attribs = array(); @@ -10404,7 +14569,7 @@ class SimplePie_Parser if ($this->current_xhtml_construct >= 0) { $this->current_xhtml_construct++; - if (end($this->namespace) == SIMPLEPIE_NAMESPACE_XHTML) + if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML) { $this->data['data'] .= '<' . end($this->element); if (isset($attribs[''])) @@ -10422,8 +14587,8 @@ class SimplePie_Parser $this->datas[] =& $this->data; $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][]; $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)); - 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') - || (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')) + 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') + || (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')) { $this->current_xhtml_construct = 0; } @@ -10436,7 +14601,7 @@ class SimplePie_Parser { $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding); } - elseif ($this->feed > 1) + else { $this->data['data'] .= $cdata; } @@ -10444,22 +14609,17 @@ class SimplePie_Parser function tag_close($parser, $tag) { - if (!$this->feed) - { - return; - } - if ($this->current_xhtml_construct >= 0) { $this->current_xhtml_construct--; - 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'))) + 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'))) { $this->data['data'] .= 'element) . '>'; } } - if ($this->current_xhtml_construct == -1) + if ($this->current_xhtml_construct === -1) { - $this->data =& $this->datas[$this->feed]; + $this->data =& $this->datas[count($this->datas) - 1]; array_pop($this->datas); } @@ -10468,7 +14628,6 @@ class SimplePie_Parser array_pop($this->xml_base); array_pop($this->xml_base_explicit); array_pop($this->xml_lang); - $this->feed--; } function split_ns($string) @@ -10483,7 +14642,19 @@ class SimplePie_Parser { $separator_length = strlen($this->separator); } - $cache[$string] = array(substr($string, 0, $pos), substr($string, $pos + $separator_length)); + $namespace = substr($string, 0, $pos); + $local_name = substr($string, $pos + $separator_length); + if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES) + { + $namespace = SIMPLEPIE_NAMESPACE_ITUNES; + } + + // Normalize the Media RSS namespaces + if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG) + { + $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS; + } + $cache[$string] = array($namespace, $local_name); } else { @@ -10495,7 +14666,7 @@ class SimplePie_Parser } /** - * @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 shortern a string while preserving HTML tags + * @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 */ class SimplePie_Sanitize { @@ -10667,7 +14838,7 @@ class SimplePie_Sanitize { if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML) { - if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/(\w+)' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data)) + 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)) { $type |= SIMPLEPIE_CONSTRUCT_HTML; } @@ -10722,9 +14893,7 @@ class SimplePie_Sanitize { foreach ($this->strip_attributes as $attrib) { - $data = preg_replace('/ '. trim($attrib) .'=("|")(\w|\s|=|-|:|;|\/|\.|\?|&|,|#|!|\(|\)|\'|'|<|>|\+|{|})*("|")/i', '', $data); - $data = preg_replace('/ '. trim($attrib) .'=(\'|')(\w|\s|=|-|:|;|\/|\.|\?|&|,|#|!|\(|\)|"|"|<|>|\+|{|})*(\'|')/i', '', $data); - $data = preg_replace('/ '. trim($attrib) .'=(\w|\s|=|-|:|;|\/|\.|\?|&|,|#|!|\(|\)|\+|{|})*/i', '', $data); + $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); } } @@ -10743,27 +14912,30 @@ class SimplePie_Sanitize { if (isset($img['attribs']['src']['data'])) { - $image_url = $img['attribs']['src']['data']; - $cache = new $this->cache_class($this->cache_location, call_user_func($this->cache_name_function, $image_url), 'spi'); + $image_url = call_user_func($this->cache_name_function, $img['attribs']['src']['data']); + $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $image_url, 'spi'); if ($cache->load()) { - $img['attribs']['src']['data'] = $this->image_handler . rawurlencode($img['attribs']['src']['data']); + $img['attribs']['src']['data'] = $this->image_handler . $image_url; $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data); } else { - $file = new $this->file_class($image_url, $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen); + $file = new $this->file_class($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen); $headers = $file->headers; - if ($file->success && ($file->status_code == 200 || ($file->status_code > 206 && $file->status_code < 300))) + if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300))) { - if (!$cache->save(array('headers' => $file->headers, 'body' => $file->body))) + if ($cache->save(array('headers' => $file->headers, 'body' => $file->body))) + { + $img['attribs']['src']['data'] = $this->image_handler . $image_url; + $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data); + } + else { - trigger_error("$cache->name is not writeable", E_USER_WARNING); + 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); } - $img['attribs']['src']['data'] = $this->image_handler . rawurlencode($img['attribs']['src']['data']); - $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data); } } } @@ -10784,7 +14956,7 @@ class SimplePie_Sanitize $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8'); } - if ($this->output_encoding != 'UTF-8') + if ($this->output_encoding !== 'UTF-8') { $data = SimplePie_Misc::change_encoding($data, 'UTF-8', $this->output_encoding); } @@ -10806,7 +14978,9 @@ class SimplePie_Sanitize if (isset($element['attribs'][$attribute]['data'])) { $element['attribs'][$attribute]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attribute]['data'], $this->base); - $data = str_replace($element['full'], SimplePie_Misc::element_implode($element), $data); + $new_element = SimplePie_Misc::element_implode($element); + $data = str_replace($element['full'], $new_element, $data); + $element['full'] = $new_element; } } } -- cgit v1.2.3