MDL-56001 lib: Upgrade simplepie to 1.4.2
authorAdrian Greeve <adrian@moodle.com>
Thu, 22 Sep 2016 02:05:04 +0000 (10:05 +0800)
committerAdrian Greeve <adrian@moodle.com>
Tue, 4 Oct 2016 01:59:25 +0000 (09:59 +0800)
35 files changed:
lib/simplepie/library/SimplePie.php [changed mode: 0644->0755]
lib/simplepie/library/SimplePie/Author.php
lib/simplepie/library/SimplePie/Cache.php
lib/simplepie/library/SimplePie/Cache/Base.php
lib/simplepie/library/SimplePie/Cache/DB.php
lib/simplepie/library/SimplePie/Cache/File.php
lib/simplepie/library/SimplePie/Cache/Memcache.php
lib/simplepie/library/SimplePie/Cache/Memcached.php [new file with mode: 0755]
lib/simplepie/library/SimplePie/Cache/MySQL.php
lib/simplepie/library/SimplePie/Cache/Redis.php [new file with mode: 0644]
lib/simplepie/library/SimplePie/Caption.php
lib/simplepie/library/SimplePie/Category.php
lib/simplepie/library/SimplePie/Content/Type/Sniffer.php
lib/simplepie/library/SimplePie/Copyright.php
lib/simplepie/library/SimplePie/Core.php
lib/simplepie/library/SimplePie/Credit.php
lib/simplepie/library/SimplePie/Decode/HTML/Entities.php
lib/simplepie/library/SimplePie/Enclosure.php
lib/simplepie/library/SimplePie/Exception.php
lib/simplepie/library/SimplePie/File.php
lib/simplepie/library/SimplePie/HTTP/Parser.php
lib/simplepie/library/SimplePie/IRI.php
lib/simplepie/library/SimplePie/Item.php
lib/simplepie/library/SimplePie/Locator.php
lib/simplepie/library/SimplePie/Misc.php
lib/simplepie/library/SimplePie/Net/IPv6.php
lib/simplepie/library/SimplePie/Parse/Date.php
lib/simplepie/library/SimplePie/Parser.php
lib/simplepie/library/SimplePie/Rating.php
lib/simplepie/library/SimplePie/Registry.php [changed mode: 0644->0755]
lib/simplepie/library/SimplePie/Restriction.php
lib/simplepie/library/SimplePie/Sanitize.php
lib/simplepie/library/SimplePie/Source.php
lib/simplepie/library/SimplePie/XML/Declaration/Parser.php
lib/simplepie/library/SimplePie/gzdecode.php

old mode 100644 (file)
new mode 100755 (executable)
index b33c635..24931b2
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * 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 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @version 1.4.1
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -50,7 +50,7 @@ define('SIMPLEPIE_NAME', 'SimplePie');
 /**
  * SimplePie Version
  */
-define('SIMPLEPIE_VERSION', '1.3.1');
+define('SIMPLEPIE_VERSION', '1.4.1');
 
 /**
  * SimplePie Build
@@ -445,6 +445,13 @@ class SimplePie
         */
        public $feed_url;
 
+       /**
+        * @var string Original feed URL, or new feed URL iff HTTP 301 Moved Permanently
+        * @see SimplePie::subscribe_url()
+        * @access private
+        */
+       public $permanent_url = null;
+
        /**
         * @var object Instance of SimplePie_File to use as a feed
         * @see SimplePie::set_file()
@@ -466,6 +473,13 @@ class SimplePie
         */
        public $timeout = 10;
 
+       /**
+        * @var array Custom curl options
+        * @see SimplePie::set_curl_options()
+        * @access private
+        */
+       public $curl_options = array();
+
        /**
         * @var bool Forces fsockopen() to be used for remote files instead
         * of cURL, even if a new enough version is installed
@@ -489,6 +503,14 @@ class SimplePie
         */
        public $cache = true;
 
+       /**
+        * @var bool Force SimplePie to fallback to expired cache, if enabled,
+        * when feed is unavailable.
+        * @see SimplePie::force_cache_fallback()
+        * @access private
+        */
+       public $force_cache_fallback = false;
+
        /**
         * @var int Cache duration (in seconds)
         * @see SimplePie::set_cache_duration()
@@ -594,6 +616,12 @@ class SimplePie
         */
        public $item_limit = 0;
 
+       /**
+        * @var bool Stores if last-modified and/or etag headers were sent with the
+        * request when checking a feed.
+        */
+       public $check_modified = false;
+
        /**
         * @var array Stores the default attributes to be stripped by strip_attributes().
         * @see SimplePie::strip_attributes()
@@ -601,6 +629,13 @@ class SimplePie
         */
        public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
 
+       /**
+        * @var array Stores the default attributes to add to different tags by add_attributes().
+        * @see SimplePie::add_attributes()
+        * @access private
+        */
+       public $add_attributes = array('audio' => array('preload' => 'none'), 'iframe' => array('sandbox' => 'allow-scripts allow-same-origin'), 'video' => array('preload' => 'none'));
+
        /**
         * @var array Stores the default tags to be stripped by strip_htmltags().
         * @see SimplePie::strip_htmltags()
@@ -637,7 +672,7 @@ class SimplePie
                if (func_num_args() > 0)
                {
                        $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
-                       trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_location() directly.', $level);
+                       trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_duration() directly.', $level);
 
                        $args = func_get_args();
                        switch (count($args)) {
@@ -728,6 +763,7 @@ class SimplePie
                else
                {
                        $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
+                       $this->permanent_url = $this->feed_url;
                }
        }
 
@@ -742,6 +778,7 @@ class SimplePie
                if ($file instanceof SimplePie_File)
                {
                        $this->feed_url = $file->url;
+                       $this->permanent_url = $this->feed_url;
                        $this->file =& $file;
                        return true;
                }
@@ -780,6 +817,19 @@ class SimplePie
                $this->timeout = (int) $timeout;
        }
 
+       /**
+        * Set custom curl options
+        *
+        * This allows you to change default curl options
+        *
+        * @since 1.0 Beta 3
+        * @param array $curl_options Curl options to add to default settings
+        */
+       public function set_curl_options(array $curl_options = array())
+       {
+               $this->curl_options = $curl_options;
+       }
+
        /**
         * Force SimplePie to use fsockopen() instead of cURL
         *
@@ -805,6 +855,21 @@ class SimplePie
                $this->cache = (bool) $enable;
        }
 
+       /**
+        * SimplePie to continue to fall back to expired cache, if enabled, when
+        * feed is unavailable.
+        *
+        * This tells SimplePie to ignore any file errors and fall back to cache
+        * instead. This only works if caching is enabled and cached content
+        * still exists.
+
+        * @param bool $enable Force use of cache on fail.
+        */
+       public function force_cache_fallback($enable = false)
+       {
+               $this->force_cache_fallback= (bool) $enable;
+       }
+
        /**
         * Set the length of time (in seconds) that the contents of a feed will be
         * cached
@@ -1073,6 +1138,7 @@ class SimplePie
                        $this->strip_comments(false);
                        $this->strip_htmltags(false);
                        $this->strip_attributes(false);
+                       $this->add_attributes(false);
                        $this->set_image_handler(false);
                }
        }
@@ -1119,16 +1185,25 @@ class SimplePie
                $this->sanitize->strip_attributes($attribs);
        }
 
+       public function add_attributes($attribs = '')
+       {
+               if ($attribs === '')
+               {
+                       $attribs = $this->add_attributes;
+               }
+               $this->sanitize->add_attributes($attribs);
+       }
+
        /**
         * Set the output encoding
         *
         * Allows you to override SimplePie's output to match that of your webpage.
         * This is useful for times when your webpages are not being served as
-        * UTF-8.  This setting will be obeyed by {@see handle_content_type()}, and
+        * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and
         * is similar to {@see set_input_encoding()}.
         *
         * It should be noted, however, that not all character encodings can support
-        * all characters.  If your page is being served as ISO-8859-1 and you try
+        * all characters. If your page is being served as ISO-8859-1 and you try
         * to display a Japanese feed, you'll likely see garbled characters.
         * Because of this, it is highly recommended to ensure that your webpages
         * are served as UTF-8.
@@ -1195,10 +1270,20 @@ class SimplePie
                $this->item_limit = (int) $limit;
        }
 
+       /**
+        * Enable throwing exceptions
+        *
+        * @param boolean $enable Should we throw exceptions, or use the old-style error property?
+        */
+       public function enable_exceptions($enable = true)
+       {
+               $this->enable_exceptions = $enable;
+       }
+
        /**
         * Initialize the feed object
         *
-        * This is what makes everything happen.  Period.  This is where all of the
+        * This is what makes everything happen. Period. This is where all of the
         * configuration options get processed, feeds are fetched, cached, and
         * parsed, and all of that other good stuff.
         *
@@ -1236,7 +1321,7 @@ class SimplePie
                // Pass whatever was set with config options over to the sanitizer.
                // Pass the classes in for legacy support; new classes should use the registry instead
                $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache'));
-               $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen);
+               $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen, $this->curl_options);
 
                if (!empty($this->multifeed_url))
                {
@@ -1265,6 +1350,7 @@ class SimplePie
 
                $this->error = null;
                $this->data = array();
+               $this->check_modified = false;
                $this->multifeed_objects = array();
                $cache = false;
 
@@ -1296,7 +1382,7 @@ class SimplePie
                // First check to see if input has been overridden.
                if ($this->input_encoding !== false)
                {
-                       $encodings[] = $this->input_encoding;
+                       $encodings[] = strtoupper($this->input_encoding);
                }
 
                $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
@@ -1318,14 +1404,14 @@ class SimplePie
                        {
                                if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
                                {
-                                       $encodings[] = $charset[1];
+                                       $encodings[] = strtoupper($charset[1]);
                                }
                                $encodings[] = 'US-ASCII';
                        }
                        // Text MIME-type default
                        elseif (substr($sniffed, 0, 5) === 'text/')
                        {
-                               $encodings[] = 'US-ASCII';
+                               $encodings[] = 'UTF-8';
                        }
                }
 
@@ -1347,7 +1433,7 @@ class SimplePie
                                $parser = $this->registry->create('Parser');
 
                                // If it's parsed fine
-                               if ($parser->parse($utf8_data, 'UTF-8'))
+                               if ($parser->parse($utf8_data, 'UTF-8', $this->permanent_url))
                                {
                                        $this->data = $parser->get_data();
                                        if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
@@ -1376,7 +1462,8 @@ class SimplePie
                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());
+                       $this->error = $this->feed_url;
+                       $this->error .= sprintf(' is invalid XML, likely due to invalid characters. XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column());
                }
                else
                {
@@ -1436,7 +1523,10 @@ class SimplePie
                                // Check if the cache has been updated
                                elseif ($cache->mtime() + $this->cache_duration < time())
                                {
-                                       // If we have last-modified and/or etag set
+                                       // Want to know if we tried to send last-modified and/or etag headers
+                                       // when requesting this file. (Note that it's up to the file to
+                                       // support this, but we don't always send the headers either.)
+                                       $this->check_modified = true;
                                        if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
                                        {
                                                $headers = array(
@@ -1451,18 +1541,28 @@ class SimplePie
                                                        $headers['if-none-match'] = $this->data['headers']['etag'];
                                                }
 
-                                               $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
+                                               $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options));
 
                                                if ($file->success)
                                                {
                                                        if ($file->status_code === 304)
                                                        {
+                                                               // Set raw_data to false here too, to signify that the cache
+                                                               // is still valid.
+                                                               $this->raw_data = false;
                                                                $cache->touch();
                                                                return true;
                                                        }
                                                }
                                                else
                                                {
+                                                       $this->check_modified = false;
+                                                       if($this->force_cache_fallback)
+                                                       {
+                                                               $cache->touch();
+                                                               return true;
+                                                       }
+
                                                        unset($file);
                                                }
                                        }
@@ -1493,7 +1593,7 @@ class SimplePie
                                $headers = array(
                                        'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
                                );
-                               $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen));
+                               $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options));
                        }
                }
                // If the file connection has an error, set SimplePie::error to that and quit
@@ -1510,19 +1610,75 @@ class SimplePie
 
                        if (!$locate->is_feed($file))
                        {
-                               // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
-                               unset($file);
+                               $copyStatusCode = $file->status_code;
+                               $copyContentType = $file->headers['content-type'];
                                try
                                {
-                                       if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)))
+                                       $microformats = false;
+                                       if (function_exists('Mf2\parse')) {
+                                               // Check for both h-feed and h-entry, as both a feed with no entries
+                                               // and a list of entries without an h-feed wrapper are both valid.
+                                               $position = 0;
+                                               while ($position = strpos($file->body, 'h-feed', $position))
+                                               {
+                                                       $start = $position < 200 ? 0 : $position - 200;
+                                                       $check = substr($file->body, $start, 400);
+                                                       if ($microformats = preg_match('/class="[^"]*h-feed/', $check))
+                                                       {
+                                                               break;
+                                                       }
+                                                       $position += 7;
+                                               }
+                                               $position = 0;
+                                               while ($position = strpos($file->body, 'h-entry', $position))
+                                               {
+                                                       $start = $position < 200 ? 0 : $position - 200;
+                                                       $check = substr($file->body, $start, 400);
+                                                       if ($microformats = preg_match('/class="[^"]*h-entry/', $check))
+                                                       {
+                                                               break;
+                                                       }
+                                                       $position += 7;
+                                               }
+                                       }
+                                       // Now also do feed discovery, but if an h-entry was found don't
+                                       // overwrite the current value of file.
+                                       $discovered = $locate->find($this->autodiscovery,
+                                                                   $this->all_discovered_feeds);
+                                       if ($microformats)
                                        {
-                                               $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.";
-                                               $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
-                                               return false;
+                                               if ($hub = $locate->get_rel_link('hub'))
+                                               {
+                                                       $self = $locate->get_rel_link('self');
+                                                       $this->store_links($file, $hub, $self);
+                                               }
+                                               // Push the current file onto all_discovered feeds so the user can
+                                               // be shown this as one of the options.
+                                               if (isset($this->all_discovered_feeds)) {
+                                                       $this->all_discovered_feeds[] = $file;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               if ($discovered)
+                                               {
+                                                       $file = $discovered;
+                                               }
+                                               else
+                                               {
+                                                       // We need to unset this so that if SimplePie::set_file() has
+                                                       // been called that object is untouched
+                                                       unset($file);
+                                                       $this->error = "A feed could not be found at `$this->feed_url`; the status code is `$copyStatusCode` and content-type is `$copyContentType`";
+                                                       $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
+                                                       return false;
+                                               }
                                        }
                                }
                                catch (SimplePie_Exception $e)
                                {
+                                       // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
+                                       unset($file);
                                        // This is usually because DOMDocument doesn't exist
                                        $this->error = $e->getMessage();
                                        $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, $e->getFile(), $e->getLine()));
@@ -1543,7 +1699,7 @@ class SimplePie
                }
 
                $this->raw_data = $file->body;
-
+               $this->permanent_url = $file->permanent_url;
                $headers = $file->headers;
                $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
                $sniffed = $sniffer->get_type();
@@ -1729,26 +1885,44 @@ class SimplePie
 
        /**
         * Get the URL for the feed
+        * 
+        * When the 'permanent' mode is enabled, returns the original feed URL,
+        * except in the case of an `HTTP 301 Moved Permanently` status response,
+        * in which case the location of the first redirection is returned.
         *
-        * May or may not be different from the URL passed to {@see set_feed_url()},
+        * When the 'permanent' mode is disabled (default),
+        * may or may not be different from the URL passed to {@see set_feed_url()},
         * depending on whether auto-discovery was used.
         *
         * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
-        * @todo If we have a perm redirect we should return the new URL
-        * @todo When we make the above change, let's support <itunes:new-feed-url> as well
+        * @todo Support <itunes:new-feed-url>
         * @todo Also, |atom:link|@rel=self
+        * @param bool $permanent Permanent mode to return only the original URL or the first redirection
+        * iff it is a 301 redirection
         * @return string|null
         */
-       public function subscribe_url()
+       public function subscribe_url($permanent = false)
        {
-               if ($this->feed_url !== null)
+               if ($permanent)
                {
-                       return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
+                       if ($this->permanent_url !== null)
+                       {
+                               // sanitize encodes ampersands which are required when used in a url.
+                               return str_replace('&amp;', '&',
+                                                  $this->sanitize($this->permanent_url,
+                                                                  SIMPLEPIE_CONSTRUCT_IRI));
+                       }
                }
                else
                {
-                       return null;
+                       if ($this->feed_url !== null)
+                       {
+                               return str_replace('&amp;', '&',
+                                                  $this->sanitize($this->feed_url,
+                                                                  SIMPLEPIE_CONSTRUCT_IRI));
+                       }
                }
+               return null;
        }
 
        /**
@@ -1963,7 +2137,21 @@ class SimplePie
         */
        public function sanitize($data, $type, $base = '')
        {
-               return $this->sanitize->sanitize($data, $type, $base);
+               try
+               {
+                       return $this->sanitize->sanitize($data, $type, $base);
+               }
+               catch (SimplePie_Exception $e)
+               {
+                       if (!$this->enable_exceptions)
+                       {
+                               $this->error = $e->getMessage();
+                               $this->registry->call('Misc', 'error', array($this->error, E_USER_WARNING, $e->getFile(), $e->getLine()));
+                               return '';
+                       }
+
+                       throw $e;
+               }
        }
 
        /**
@@ -2014,7 +2202,7 @@ class SimplePie
         * Get a category for the feed
         *
         * @since Unknown
-        * @param int $key The category that you want to return.  Remember that arrays begin with 0, not 1
+        * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
         * @return SimplePie_Category|null
         */
        public function get_category($key = 0)
@@ -2099,7 +2287,7 @@ class SimplePie
         * Get an author for the feed
         *
         * @since 1.1
-        * @param int $key The author that you want to return.  Remember that arrays begin with 0, not 1
+        * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
         * @return SimplePie_Author|null
         */
        public function get_author($key = 0)
@@ -2197,7 +2385,7 @@ class SimplePie
         * Get a contributor for the feed
         *
         * @since 1.1
-        * @param int $key The contrbutor that you want to return.  Remember that arrays begin with 0, not 1
+        * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
         * @return SimplePie_Author|null
         */
        public function get_contributor($key = 0)
@@ -2283,7 +2471,7 @@ class SimplePie
         * Get a single link for the feed
         *
         * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
-        * @param int $key The link that you want to return.  Remember that arrays begin with 0, not 1
+        * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
         * @param string $rel The relationship of the link to return
         * @return string|null Link URL
         */
@@ -2393,6 +2581,12 @@ class SimplePie
                {
                        return $this->data['links'][$rel];
                }
+               else if (isset($this->data['headers']['link']) &&
+                        preg_match('/<([^>]+)>; rel='.preg_quote($rel).'/',
+                                   $this->data['headers']['link'], $match))
+               {
+                       return array($match[1]);
+               }
                else
                {
                        return null;
@@ -2794,7 +2988,7 @@ class SimplePie
         *
         * @see get_item_quantity()
         * @since Beta 2
-        * @param int $key The item that you want to return.  Remember that arrays begin with 0, not 1
+        * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1
         * @return SimplePie_Item|null
         */
        public function get_item($key = 0)
@@ -2821,7 +3015,7 @@ class SimplePie
         * @since Beta 2
         * @param int $start Index to start at
         * @param int $end Number of items to return. 0 for all items after `$start`
-        * @return array|null List of {@see SimplePie_Item} objects
+        * @return SimplePie_Item[]|null List of {@see SimplePie_Item} objects
         */
        public function get_items($start = 0, $end = 0)
        {
@@ -2830,96 +3024,81 @@ class SimplePie
                        if (!empty($this->multifeed_objects))
                        {
                                $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
+                               if (empty($this->data['items']))
+                               {
+                                       return array();
+                               }
+                               return $this->data['items'];
                        }
-                       else
+                       $this->data['items'] = array();
+                       if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
                        {
-                               $this->data['items'] = array();
-                               if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
+                               $keys = array_keys($items);
+                               foreach ($keys as $key)
                                {
-                                       $keys = array_keys($items);
-                                       foreach ($keys as $key)
-                                       {
-                                               $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
-                                       }
+                                       $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
                                }
-                               if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
+                       }
+                       if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
+                       {
+                               $keys = array_keys($items);
+                               foreach ($keys as $key)
                                {
-                                       $keys = array_keys($items);
-                                       foreach ($keys as $key)
-                                       {
-                                               $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
-                                       }
+                                       $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
                                }
-                               if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
+                       }
+                       if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
+                       {
+                               $keys = array_keys($items);
+                               foreach ($keys as $key)
                                {
-                                       $keys = array_keys($items);
-                                       foreach ($keys as $key)
-                                       {
-                                               $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
-                                       }
+                                       $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
                                }
-                               if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
+                       }
+                       if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
+                       {
+                               $keys = array_keys($items);
+                               foreach ($keys as $key)
                                {
-                                       $keys = array_keys($items);
-                                       foreach ($keys as $key)
-                                       {
-                                               $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
-                                       }
+                                       $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
                                }
-                               if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
+                       }
+                       if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
+                       {
+                               $keys = array_keys($items);
+                               foreach ($keys as $key)
                                {
-                                       $keys = array_keys($items);
-                                       foreach ($keys as $key)
-                                       {
-                                               $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
-                                       }
+                                       $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
                                }
                        }
                }
 
-               if (!empty($this->data['items']))
+               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 && empty($this->multifeed_objects))
-                       {
-                               if (!isset($this->data['ordered_items']))
-                               {
-                                       $do_sort = true;
-                                       foreach ($this->data['items'] as $item)
-                                       {
-                                               if (!$item->get_date('U'))
-                                               {
-                                                       $do_sort = false;
-                                                       break;
-                                               }
-                                       }
-                                       $item = null;
-                                       $this->data['ordered_items'] = $this->data['items'];
-                                       if ($do_sort)
-                                       {
-                                               usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
-                                       }
-                               }
-                               $items = $this->data['ordered_items'];
-                       }
-                       else
-                       {
-                               $items = $this->data['items'];
-                       }
+                       return array();
+               }
 
-                       // Slice the data as desired
-                       if ($end === 0)
-                       {
-                               return array_slice($items, $start);
-                       }
-                       else
+               if ($this->order_by_date)
+               {
+                       if (!isset($this->data['ordered_items']))
                        {
-                               return array_slice($items, $start, $end);
-                       }
+                               $this->data['ordered_items'] = $this->data['items'];
+                               usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
+                       }
+                       $items = $this->data['ordered_items'];
                }
                else
                {
-                       return array();
+                       $items = $this->data['items'];
+               }
+               // Slice the data as desired
+               if ($end === 0)
+               {
+                       return array_slice($items, $start);
+               }
+               else
+               {
+                       return array_slice($items, $start, $end);
                }
        }
 
@@ -2992,7 +3171,19 @@ class SimplePie
         */
        public static function sort_items($a, $b)
        {
-               return $a->get_date('U') <= $b->get_date('U');
+               $a_date = $a->get_date('U');
+               $b_date = $b->get_date('U');
+               if ($a_date && $b_date) {
+                       return $a_date > $b_date ? -1 : 1;
+               }
+               // Sort items without dates to the top.
+               if ($a_date) {
+                       return 1;
+               }
+               if ($b_date) {
+                       return -1;
+               }
+               return 0;
        }
 
        /**
@@ -3025,20 +3216,7 @@ class SimplePie
                                }
                        }
 
-                       $do_sort = true;
-                       foreach ($items as $item)
-                       {
-                               if (!$item->get_date('U'))
-                               {
-                                       $do_sort = false;
-                                       break;
-                               }
-                       }
-                       $item = null;
-                       if ($do_sort)
-                       {
-                               usort($items, array(get_class($urls[0]), 'sort_items'));
-                       }
+                       usort($items, array(get_class($urls[0]), 'sort_items'));
 
                        if ($end === 0)
                        {
@@ -3055,4 +3233,42 @@ class SimplePie
                        return array();
                }
        }
+
+       /**
+        * Store PubSubHubbub links as headers
+        *
+        * There is no way to find PuSH links in the body of a microformats feed,
+        * so they are added to the headers when found, to be used later by get_links.
+        * @param SimplePie_File $file
+        * @param string $hub
+        * @param string $self
+        */
+       private function store_links(&$file, $hub, $self) {
+               if (isset($file->headers['link']['hub']) ||
+                         (isset($file->headers['link']) &&
+                          preg_match('/rel=hub/', $file->headers['link'])))
+               {
+                       return;
+               }
+
+               if ($hub)
+               {
+                       if (isset($file->headers['link']))
+                       {
+                               if ($file->headers['link'] !== '')
+                               {
+                                       $file->headers['link'] = ', ';
+                               }
+                       }
+                       else
+                       {
+                               $file->headers['link'] = '';
+                       }
+                       $file->headers['link'] .= '<'.$hub.'>; rel=hub';
+                       if ($self)
+                       {
+                               $file->headers['link'] .= ', <'.$self.'>; rel=self';
+                       }
+               }
+       }
 }
index bbf3812..e6768ff 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index 75586d7..d98cc65 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -62,8 +61,10 @@ class SimplePie_Cache
         * @var array
         */
        protected static $handlers = array(
-               'mysql' => 'SimplePie_Cache_MySQL',
-               'memcache' => 'SimplePie_Cache_Memcache',
+               'mysql'     => 'SimplePie_Cache_MySQL',
+               'memcache'  => 'SimplePie_Cache_Memcache',
+               'memcached' => 'SimplePie_Cache_Memcached',
+               'redis'     => 'SimplePie_Cache_Redis'
        );
 
        /**
index 937e346..333fb05 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index ac509ae..7e8f775 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index 5797b3a..6ba6c5f 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -136,11 +135,7 @@ class SimplePie_Cache_File implements SimplePie_Cache_Base
         */
        public function mtime()
        {
-               if (file_exists($this->name))
-               {
-                       return filemtime($this->name);
-               }
-               return false;
+               return @filemtime($this->name);
        }
 
        /**
@@ -150,11 +145,7 @@ class SimplePie_Cache_File implements SimplePie_Cache_Base
         */
        public function touch()
        {
-               if (file_exists($this->name))
-               {
-                       return touch($this->name);
-               }
-               return false;
+               return @touch($this->name);
        }
 
        /**
index fd44780..5190eef 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -95,10 +94,8 @@ class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
                                'prefix' => 'simplepie_',
                        ),
                );
-               $parsed = SimplePie_Cache::parse_URL($location);
-               $this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
-               $this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
-               $this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
+               $this->options = SimplePie_Misc::array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
+
                $this->name = $this->options['extras']['prefix'] . md5("$name:$type");
 
                $this->cache = new Memcache();
@@ -147,7 +144,7 @@ class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
 
                if ($data !== false)
                {
-                       // essentially ignore the mtime because Memcache expires on it's own
+                       // essentially ignore the mtime because Memcache expires on its own
                        return time();
                }
 
@@ -165,7 +162,7 @@ class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
 
                if ($data !== false)
                {
-                       return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
+                       return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
                }
 
                return false;
diff --git a/lib/simplepie/library/SimplePie/Cache/Memcached.php b/lib/simplepie/library/SimplePie/Cache/Memcached.php
new file mode 100755 (executable)
index 0000000..1f73b38
--- /dev/null
@@ -0,0 +1,166 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ *     * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ *       to endorse or promote products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Caches data to memcached
+ *
+ * Registered for URLs with the "memcached" protocol
+ *
+ * For example, `memcached://localhost:11211/?timeout=3600&prefix=sp_` will
+ * connect to memcached on `localhost` on port 11211. All tables will be
+ * prefixed with `sp_` and data will expire after 3600 seconds
+ *
+ * @package    SimplePie
+ * @subpackage Caching
+ * @author     Paul L. McNeely
+ * @uses       Memcached
+ */
+class SimplePie_Cache_Memcached implements SimplePie_Cache_Base
+{
+    /**
+     * Memcached instance
+     * @var Memcached
+     */
+    protected $cache;
+
+    /**
+     * Options
+     * @var array
+     */
+    protected $options;
+
+    /**
+     * Cache name
+     * @var string
+     */
+    protected $name;
+
+    /**
+     * Create a new cache object
+     * @param string $location Location string (from SimplePie::$cache_location)
+     * @param string $name     Unique ID for the cache
+     * @param string $type     Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
+     */
+    public function __construct($location, $name, $type) {
+        $this->options = array(
+            'host'   => '127.0.0.1',
+            'port'   => 11211,
+            'extras' => array(
+                'timeout' => 3600, // one hour
+                'prefix'  => 'simplepie_',
+            ),
+        );
+        $this->options = SimplePie_Misc::array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
+
+        $this->name = $this->options['extras']['prefix'] . md5("$name:$type");
+
+        $this->cache = new Memcached();
+        $this->cache->addServer($this->options['host'], (int)$this->options['port']);
+    }
+
+    /**
+     * Save data to the cache
+     * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
+     * @return bool Successfulness
+     */
+    public function save($data) {
+        if ($data instanceof SimplePie) {
+            $data = $data->data;
+        }
+
+        return $this->setData(serialize($data));
+    }
+
+    /**
+     * Retrieve the data saved to the cache
+     * @return array Data for SimplePie::$data
+     */
+    public function load() {
+        $data = $this->cache->get($this->name);
+
+        if ($data !== false) {
+            return unserialize($data);
+        }
+        return false;
+    }
+
+    /**
+     * Retrieve the last modified time for the cache
+     * @return int Timestamp
+     */
+    public function mtime() {
+        $data = $this->cache->get($this->name . '_mtime');
+        return (int) $data;
+    }
+
+    /**
+     * Set the last modified time to the current time
+     * @return bool Success status
+     */
+    public function touch() {
+        $data = $this->cache->get($this->name);
+        return $this->setData($data);
+    }
+
+    /**
+     * Remove the cache
+     * @return bool Success status
+     */
+    public function unlink() {
+        return $this->cache->delete($this->name, 0);
+    }
+
+    /**
+     * Set the last modified time and data to Memcached
+     * @return bool Success status
+     */
+    private function setData($data) {
+
+        if ($data !== false) {
+            $this->cache->set($this->name . '_mtime', time(), (int)$this->options['extras']['timeout']);
+            return $this->cache->set($this->name, $data, (int)$this->options['extras']['timeout']);
+        }
+
+        return false;
+    }
+}
index d53ebc1..8686b6c 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -94,9 +93,11 @@ class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
                        'path' => '',
                        'extras' => array(
                                'prefix' => '',
+                               'cache_purge_time' => 2592000
                        ),
                );
-               $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
+               
+               $this->options = SimplePie_Misc::array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
 
                // Path is prefixed with a "/"
                $this->options['dbname'] = substr($this->options['path'], 1);
@@ -130,16 +131,20 @@ class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
                        $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))');
                        if ($query === false)
                        {
+                               trigger_error("Can't create " . $this->options['extras']['prefix'] . "cache_data table, check permissions", E_USER_WARNING);
                                $this->mysql = null;
+                               return;
                        }
                }
 
                if (!in_array($this->options['extras']['prefix'] . 'items', $db))
                {
-                       $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
+                       $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` MEDIUMBLOB NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
                        if ($query === false)
                        {
+                               trigger_error("Can't create " . $this->options['extras']['prefix'] . "items table, check permissions", E_USER_WARNING);
                                $this->mysql = null;
+                               return;
                        }
                }
        }
@@ -157,6 +162,17 @@ class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
                        return false;
                }
 
+               $query = $this->mysql->prepare('DELETE i, cd FROM `' . $this->options['extras']['prefix'] . 'cache_data` cd, ' .
+                       '`' . $this->options['extras']['prefix'] . 'items` i ' .
+                       'WHERE cd.id = i.feed_id ' .
+                       'AND cd.mtime < (unix_timestamp() - :purge_time)');
+               $query->bindValue(':purge_time', $this->options['extras']['cache_purge_time']);
+
+               if (!$query->execute())
+               {
+                       return false;
+               }
+
                if ($data instanceof SimplePie)
                {
                        $data = clone $data;
diff --git a/lib/simplepie/library/SimplePie/Cache/Redis.php b/lib/simplepie/library/SimplePie/Cache/Redis.php
new file mode 100644 (file)
index 0000000..04d72c7
--- /dev/null
@@ -0,0 +1,166 @@
+<?php
+
+/**
+ * SimplePie Redis Cache Extension
+ *
+ * @package SimplePie
+ * @author Jan Kozak <galvani78@gmail.com>
+ * @link http://galvani.cz/
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @version 0.2.9
+ */
+
+
+/**
+ * Caches data to redis
+ *
+ * Registered for URLs with the "redis" protocol
+ *
+ * For example, `redis://localhost:6379/?timeout=3600&prefix=sp_&dbIndex=0` will
+ * connect to redis on `localhost` on port 6379. All tables will be
+ * prefixed with `simple_primary-` and data will expire after 3600 seconds
+ *
+ * @package SimplePie
+ * @subpackage Caching
+ * @uses Redis
+ */
+class SimplePie_Cache_Redis implements SimplePie_Cache_Base {
+    /**
+     * Redis instance
+     *
+     * @var \Redis
+     */
+    protected $cache;
+
+    /**
+     * Options
+     *
+     * @var array
+     */
+    protected $options;
+
+    /**
+     * Cache name
+     *
+     * @var string
+     */
+    protected $name;
+
+    /**
+     * Cache Data
+     *
+     * @var type
+     */
+    protected $data;
+
+    /**
+     * Create a new cache object
+     *
+     * @param string $location Location string (from SimplePie::$cache_location)
+     * @param string $name Unique ID for the cache
+     * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
+     */
+    public function __construct($location, $name, $options = null) {
+        //$this->cache = \flow\simple\cache\Redis::getRedisClientInstance();
+        $parsed = SimplePie_Cache::parse_URL($location);
+        $redis = new Redis();
+        $redis->connect($parsed['host'], $parsed['port']);
+        $this->cache = $redis;
+
+        if (!is_null($options) && is_array($options)) {
+            $this->options = $options;
+        } else {
+            $this->options = array (
+                'prefix' => 'rss:simple_primary:',
+                'expire' => 0,
+            );
+        }
+
+        $this->name = $this->options['prefix'] . $name;
+    }
+
+    /**
+     * @param \Redis $cache
+     */
+    public function setRedisClient(\Redis $cache) {
+        $this->cache = $cache;
+    }
+
+    /**
+     * Save data to the cache
+     *
+     * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
+     * @return bool Successfulness
+     */
+    public function save($data) {
+        if ($data instanceof SimplePie) {
+            $data = $data->data;
+        }
+        $response = $this->cache->set($this->name, serialize($data));
+        if ($this->options['expire']) {
+            $this->cache->expire($this->name, $this->options['expire']);
+        }
+
+        return $response;
+    }
+
+    /**
+     * Retrieve the data saved to the cache
+     *
+     * @return array Data for SimplePie::$data
+     */
+    public function load() {
+        $data = $this->cache->get($this->name);
+
+        if ($data !== false) {
+            return unserialize($data);
+        }
+        return false;
+    }
+
+    /**
+     * Retrieve the last modified time for the cache
+     *
+     * @return int Timestamp
+     */
+    public function mtime() {
+
+        $data = $this->cache->get($this->name);
+
+        if ($data !== false) {
+            return time();
+        }
+
+        return false;
+    }
+
+    /**
+     * Set the last modified time to the current time
+     *
+     * @return bool Success status
+     */
+    public function touch() {
+
+        $data = $this->cache->get($this->name);
+
+        if ($data !== false) {
+            $return = $this->cache->set($this->name, $data);
+            if ($this->options['expire']) {
+                return $this->cache->expire($this->name, $this->ttl);
+            }
+            return $return;
+        }
+
+        return false;
+    }
+
+    /**
+     * Remove the cache
+     *
+     * @return bool Success status
+     */
+    public function unlink() {
+        return $this->cache->set($this->name, null);
+    }
+
+}
index 52922c5..abf07de 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index ad0407b..92d511e 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index 20d053d..a681026 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index 57c535a..3f3d07d 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index 46d9966..c856ba3 100644 (file)
@@ -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-2009, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index d3a3442..9bad9ef 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index 069e8d8..de3f2cb 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -169,7 +168,6 @@ class SimplePie_Decode_HTML_Entities
                        case "\x09":
                        case "\x0A":
                        case "\x0B":
-                       case "\x0B":
                        case "\x0C":
                        case "\x20":
                        case "\x3C":
index 5567437..15060e1 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -451,7 +450,7 @@ class SimplePie_Enclosure
        /**
         * Get the duration of the enclosure
         *
-        * @param string $convert Convert seconds into hh:mm:ss
+        * @param bool $convert Convert seconds into hh:mm:ss
         * @return string|int|null 'hh:mm:ss' string if `$convert` was specified, otherwise integer (or null if none found)
         */
        public function get_duration($convert = false)
@@ -942,7 +941,7 @@ class SimplePie_Enclosure
         * - `height` (integer): The height of the embedded media. Accepts any
         *    numeric pixel value (such as `360`) or `auto`. Defaults to `auto`,
         *    and it is recommended that you use this default.
-        * - `loop` (boolean): Do you want the media to loop when its done?
+        * - `loop` (boolean): Do you want the media to loop when it's done?
         *    Defaults to `false`.
         * - `mediaplayer` (string): The location of the included
         *    `mediaplayer.swf` file. This allows for the playback of Flash Video
index 73e104d..53c015e 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.4-dev
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index b7d1a2a..a609adf 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -64,8 +63,9 @@ class SimplePie_File
        var $redirects = 0;
        var $error;
        var $method = SIMPLEPIE_FILE_SOURCE_NONE;
+       var $permanent_url;
 
-       public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
+       public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false, $curl_options = array())
        {
                if (class_exists('idna_convert'))
                {
@@ -74,6 +74,7 @@ class SimplePie_File
                        $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
                }
                $this->url = $url;
+               $this->permanent_url = $url;
                $this->useragent = $useragent;
                if (preg_match('/^http(s)?:\/\//i', $url))
                {
@@ -102,6 +103,7 @@ class SimplePie_File
                                curl_setopt($fp, CURLOPT_URL, $url);
                                curl_setopt($fp, CURLOPT_HEADER, 1);
                                curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
+                               curl_setopt($fp, CURLOPT_FAILONERROR, 1);
                                curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
                                curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
                                curl_setopt($fp, CURLOPT_REFERER, $url);
@@ -112,6 +114,9 @@ class SimplePie_File
                                        curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
                                        curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
                                }
+                               foreach ($curl_options as $curl_param => $curl_value) {
+                                       curl_setopt($fp, $curl_param, $curl_value);
+                               }
 
                                $this->headers = curl_exec($fp);
                                if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
@@ -126,7 +131,10 @@ class SimplePie_File
                                }
                                else
                                {
-                                       $info = curl_getinfo($fp);
+                                       // Use the updated url provided by curl_getinfo after any redirects.
+                                       if ($info = curl_getinfo($fp)) {
+                                               $this->url = $info['url'];
+                                       }
                                        curl_close($fp);
                                        $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
                                        $this->headers = array_pop($this->headers);
@@ -134,13 +142,16 @@ class SimplePie_File
                                        if ($parser->parse())
                                        {
                                                $this->headers = $parser->headers;
-                                               $this->body = $parser->body;
+                                               $this->body = trim($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->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+                                                       $previousStatusCode = $this->status_code;
+                                                       $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+                                                       $this->permanent_url = ($previousStatusCode == 301) ? $location : $url;
+                                                       return;
                                                }
                                        }
                                }
@@ -216,13 +227,16 @@ class SimplePie_File
                                                if ($parser->parse())
                                                {
                                                        $this->headers = $parser->headers;
-                                                       $this->body = $parser->body;
+                                                       $this->body = trim($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->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+                                                               $previousStatusCode = $this->status_code;
+                                                               $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+                                                               $this->permanent_url = ($previousStatusCode == 301) ? $location : $url;
+                                                               return;
                                                        }
                                                        if (isset($this->headers['content-encoding']))
                                                        {
@@ -239,7 +253,7 @@ class SimplePie_File
                                                                                }
                                                                                else
                                                                                {
-                                                                                       $this->body = $decoder->data;
+                                                                                       $this->body = trim($decoder->data);
                                                                                }
                                                                                break;
 
@@ -282,7 +296,7 @@ class SimplePie_File
                else
                {
                        $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
-                       if (!$this->body = file_get_contents($url))
+                       if (empty($url) || !($this->body = trim(file_get_contents($url))))
                        {
                                $this->error = 'file_get_contents could not read the file';
                                $this->success = false;
index bff2222..63ae1e0 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index d3198c0..2b3fbaf 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -259,6 +258,15 @@ class SimplePie_IRI
                $this->set_iri($iri);
        }
 
+       /**
+        * Clean up
+        */
+       public function __destruct() {
+           $this->set_iri(null, true);
+           $this->set_path(null, true);
+           $this->set_authority(null, true);
+       }
+
        /**
         * Create a new IRI object by resolving a relative IRI
         *
@@ -768,24 +776,20 @@ class SimplePie_IRI
         */
        public function is_valid()
        {
-               $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
-               if ($this->ipath !== '' &&
-                       (
-                               $isauthority && (
-                                       $this->ipath[0] !== '/' ||
-                                       substr($this->ipath, 0, 2) === '//'
-                               ) ||
-                               (
-                                       $this->scheme === null &&
-                                       !$isauthority &&
-                                       strpos($this->ipath, ':') !== false &&
-                                       (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
-                               )
-                       )
-               )
-               {
-                       return false;
-               }
+               if ($this->ipath === '') return true;
+
+               $isauthority = $this->iuserinfo !== null || $this->ihost !== null ||
+                       $this->port !== null;
+               if ($isauthority && $this->ipath[0] === '/') return true;
+
+               if (!$isauthority && (substr($this->ipath, 0, 2) === '//')) return false;
+
+               // Relative urls cannot have a colon in the first path segment (and the
+               // slashes themselves are not included so skip the first character).
+               if (!$this->scheme && !$isauthority &&
+                   strpos($this->ipath, ':') !== false &&
+                   strpos($this->ipath, '/', 1) !== false &&
+                   strpos($this->ipath, ':') < strpos($this->ipath, '/', 1)) return false;
 
                return true;
        }
@@ -797,9 +801,14 @@ class SimplePie_IRI
         * @param string $iri
         * @return bool
         */
-       public function set_iri($iri)
+       public function set_iri($iri, $clear_cache = false)
        {
                static $cache;
+               if ($clear_cache) 
+               {
+                       $cache = null;
+                       return;
+               }
                if (!$cache)
                {
                        $cache = array();
@@ -879,9 +888,14 @@ class SimplePie_IRI
         * @param string $authority
         * @return bool
         */
-       public function set_authority($authority)
+       public function set_authority($authority, $clear_cache = false)
        {
                static $cache;
+               if ($clear_cache)
+               {
+                       $cache = null;
+                       return;
+               }
                if (!$cache)
                        $cache = array();
 
@@ -1049,9 +1063,14 @@ class SimplePie_IRI
         * @param string $ipath
         * @return bool
         */
-       public function set_path($ipath)
+       public function set_path($ipath, $clear_cache = false)
        {
                static $cache;
+               if ($clear_cache) 
+               {
+                       $cache = null;
+                       return;
+               }
                if (!$cache)
                {
                        $cache = array();
index a77574b..5ffc2d2 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -203,14 +202,13 @@ class SimplePie_Item
         *
         * Uses `<atom:id>`, `<guid>`, `<dc:identifier>` or the `about` attribute
         * for RDF. If none of these are supplied (or `$hash` is true), creates an
-        * MD5 hash based on the permalink and title. If either of those are not
-        * supplied, creates a hash based on the full feed data.
+        * MD5 hash based on the permalink, title and content.
         *
         * @since Beta 2
         * @param boolean $hash Should we force using a hash instead of the supplied ID?
         * @return string
         */
-       public function get_id($hash = false)
+       public function get_id($hash = false, $fn = '')
        {
                if (!$hash)
                {
@@ -238,23 +236,10 @@ class SimplePie_Item
                        {
                                return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT);
                        }
-                       elseif (($return = $this->get_permalink()) !== null)
-                       {
-                               return $return;
-                       }
-                       elseif (($return = $this->get_title()) !== null)
-                       {
-                               return $return;
-                       }
-               }
-               if ($this->get_permalink() !== null || $this->get_title() !== null)
-               {
-                       return md5($this->get_permalink() . $this->get_title());
-               }
-               else
-               {
-                       return md5(serialize($this->data));
                }
+               if ($fn === '' || !is_callable($fn)) $fn = 'md5';
+               return call_user_func($fn,
+                      $this->get_permalink().$this->get_title().$this->get_content());
        }
 
        /**
@@ -406,6 +391,30 @@ class SimplePie_Item
                        return null;
                }
        }
+       
+       /**
+        * Get the media:thumbnail of the item
+        *
+        * Uses `<media:thumbnail>`
+        *
+        * 
+        * @return array|null
+        */
+       public function get_thumbnail()
+       {
+               if (!isset($this->data['thumbnail']))
+               {
+                       if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
+                       {
+                               $this->data['thumbnail'] = $return[0]['attribs'][''];
+                       }
+                       else
+                       {
+                               $this->data['thumbnail'] = null;
+                       }
+               }
+               return $this->data['thumbnail'];
+       }       
 
        /**
         * Get a category for the item
@@ -433,7 +442,7 @@ class SimplePie_Item
         * Uses `<atom:category>`, `<category>` or `<dc:subject>`
         *
         * @since Beta 3
-        * @return array|null List of {@see SimplePie_Category} objects
+        * @return SimplePie_Category[]|null List of {@see SimplePie_Category} objects
         */
        public function get_categories()
        {
@@ -446,15 +455,15 @@ class SimplePie_Item
                        $label = null;
                        if (isset($category['attribs']['']['term']))
                        {
-                               $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
+                               $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_HTML);
                        }
                        if (isset($category['attribs']['']['scheme']))
                        {
-                               $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+                               $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_HTML);
                        }
                        if (isset($category['attribs']['']['label']))
                        {
-                               $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+                               $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_HTML);
                        }
                        $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
                }
@@ -462,10 +471,10 @@ class SimplePie_Item
                {
                        // 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);
+                       $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_HTML);
                        if (isset($category['attribs']['']['domain']))
                        {
-                               $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
+                               $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_HTML);
                        }
                        else
                        {
@@ -475,11 +484,11 @@ class SimplePie_Item
                }
                foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
                {
-                       $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+                       $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_HTML), null, null));
                }
                foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
                {
-                       $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+                       $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_HTML), null, null));
                }
 
                if (!empty($categories))
@@ -616,7 +625,7 @@ class SimplePie_Item
                        $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);
+                               $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
                        }
                        if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
                        {
@@ -624,7 +633,7 @@ class SimplePie_Item
                        }
                        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);
+                               $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
                        }
                        if ($name !== null || $email !== null || $uri !== null)
                        {
@@ -638,7 +647,7 @@ class SimplePie_Item
                        $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);
+                               $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
                        }
                        if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
                        {
@@ -646,7 +655,7 @@ class SimplePie_Item
                        }
                        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);
+                               $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
                        }
                        if ($name !== null || $email !== null || $url !== null)
                        {
@@ -655,19 +664,19 @@ class SimplePie_Item
                }
                if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
                {
-                       $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)));
+                       $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_HTML)));
                }
                foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
                {
-                       $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+                       $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_HTML), null, null));
                }
                foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
                {
-                       $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+                       $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_HTML), null, null));
                }
                foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
                {
-                       $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+                       $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_HTML), null, null));
                }
 
                if (!empty($authors))
@@ -738,31 +747,31 @@ class SimplePie_Item
                        {
                                $this->data['date']['raw'] = $return[0]['data'];
                        }
-                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
+                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
                        {
                                $this->data['date']['raw'] = $return[0]['data'];
                        }
-                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
+                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
                        {
                                $this->data['date']['raw'] = $return[0]['data'];
                        }
-                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
+                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
                        {
                                $this->data['date']['raw'] = $return[0]['data'];
                        }
-                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
+                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
                        {
                                $this->data['date']['raw'] = $return[0]['data'];
                        }
-                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
+                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
                        {
                                $this->data['date']['raw'] = $return[0]['data'];
                        }
-                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
+                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
                        {
                                $this->data['date']['raw'] = $return[0]['data'];
                        }
-                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
+                       elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
                        {
                                $this->data['date']['raw'] = $return[0]['data'];
                        }
@@ -821,7 +830,7 @@ class SimplePie_Item
                        if (!empty($this->data['updated']['raw']))
                        {
                                $parser = $this->registry->call('Parse_Date', 'get');
-                               $this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']);
+                               $this->data['updated']['parsed'] = $parser->parse($this->data['updated']['raw']);
                        }
                        else
                        {
@@ -1080,8 +1089,8 @@ class SimplePie_Item
         *
         * @since Beta 2
         * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
-        * @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).
-        * @return array|null List of SimplePie_Enclosure items
+        * @todo If an element exists at a level, but its value is empty, we should fall back to the value from the parent (if it exists).
+        * @return SimplePie_Enclosure[]|null List of SimplePie_Enclosure items
         */
        public function get_enclosures()
        {
@@ -2658,7 +2667,9 @@ class SimplePie_Item
                                                // PLAYER
                                                if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
                                                {
-                                                       $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+                                                       if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'])) {
+                                                               $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+                                                       }
                                                }
                                                else
                                                {
@@ -2733,7 +2744,9 @@ class SimplePie_Item
                                                {
                                                        foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
                                                        {
-                                                               $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+                                                               if (isset($thumbnail['attribs']['']['url'])) {
+                                                                       $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+                                                               }
                                                        }
                                                        if (is_array($thumbnails))
                                                        {
index 57e910c..1010066 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -121,34 +120,41 @@ class SimplePie_Locator
                {
                        if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
                        {
-                               return $working;
+                               return $working[0];
                        }
 
                        if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
                        {
-                               return $working;
+                               return $working[0];
                        }
 
                        if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
                        {
-                               return $working;
+                               return $working[0];
                        }
 
                        if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
                        {
-                               return $working;
+                               return $working[0];
                        }
                }
                return null;
        }
 
-       public function is_feed($file)
+       public function is_feed($file, $check_html = false)
        {
                if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
                {
                        $sniffer = $this->registry->create('Content_Type_Sniffer', array($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')))
+                       $mime_types = array('application/rss+xml', 'application/rdf+xml',
+                                           'text/rdf', 'application/atom+xml', 'text/xml',
+                                           'application/xml', 'application/x-rss+xml');
+                       if ($check_html)
+                       {
+                               $mime_types[] = 'text/html';
+                       }
+                       if (in_array($sniffed, $mime_types))
                        {
                                return true;
                        }
@@ -242,14 +248,14 @@ class SimplePie_Locator
                                        continue;
                                }
 
-                               if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && $link->hasAttribute('type') && in_array(strtolower($this->registry->call('Misc', 'parse_mime', array($link->getAttribute('type')))), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href]))
+                               if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && $link->hasAttribute('type') && in_array(strtolower($this->registry->call('Misc', 'parse_mime', array($link->getAttribute('type')))), array('text/html', 'application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href]))
                                {
                                        $this->checked_feeds++;
                                        $headers = array(
                                                'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
                                        );
                                        $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent));
-                                       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))
+                                       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, true))
                                        {
                                                $feeds[$href] = $feed;
                                        }
@@ -275,9 +281,9 @@ class SimplePie_Locator
                        {
                                $href = trim($link->getAttribute('href'));
                                $parsed = $this->registry->call('Misc', 'parse_url', array($href));
-                               if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
+                               if ($parsed['scheme'] === '' || preg_match('/^(https?|feed)?$/i', $parsed['scheme']))
                                {
-                                       if ($this->base_location < $link->getLineNo())
+                                       if (method_exists($link, 'getLineNo') && $this->base_location < $link->getLineNo())
                                        {
                                                $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
                                        }
@@ -312,6 +318,57 @@ class SimplePie_Locator
                return null;
        }
 
+       public function get_rel_link($rel)
+       {
+               if ($this->dom === null)
+               {
+                       throw new SimplePie_Exception('DOMDocument not found, unable to use '.
+                                                     'locator');
+               }
+               if (!class_exists('DOMXpath'))
+               {
+                       throw new SimplePie_Exception('DOMXpath not found, unable to use '.
+                                                     'get_rel_link');
+               }
+
+               $xpath = new DOMXpath($this->dom);
+               $query = '//a[@rel and @href] | //link[@rel and @href]';
+               foreach ($xpath->query($query) as $link)
+               {
+                       $href = trim($link->getAttribute('href'));
+                       $parsed = $this->registry->call('Misc', 'parse_url', array($href));
+                       if ($parsed['scheme'] === '' ||
+                           preg_match('/^https?$/i', $parsed['scheme']))
+                       {
+                               if (method_exists($link, 'getLineNo') &&
+                                   $this->base_location < $link->getLineNo())
+                               {
+                                       $href =
+                                               $this->registry->call('Misc', 'absolutize_url',
+                                                                     array(trim($link->getAttribute('href')),
+                                                                           $this->base));
+                               }
+                               else
+                               {
+                                       $href =
+                                               $this->registry->call('Misc', 'absolutize_url',
+                                                                     array(trim($link->getAttribute('href')),
+                                                                           $this->http_base));
+                               }
+                               if ($href === false)
+                               {
+                                       return null;
+                               }
+                               $rel_values = explode(' ', strtolower($link->getAttribute('rel')));
+                               if (in_array($rel, $rel_values))
+                               {
+                                       return $href;
+                               }
+                       }
+               }
+               return null;
+       }
+
        public function extension(&$array)
        {
                foreach ($array as $key => $value)
@@ -330,7 +387,7 @@ class SimplePie_Locator
                                $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent));
                                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;
+                                       return array($feed);
                                }
                                else
                                {
@@ -358,7 +415,7 @@ class SimplePie_Locator
                                $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent));
                                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;
+                                       return array($feed);
                                }
                                else
                                {
index 5d7367f..c1ae3b5 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -124,7 +123,7 @@ class SimplePie_Misc
                                                {
                                                        $attribs[$j][2] = $attribs[$j][1];
                                                }
-                                               $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
+                                               $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]));
                                        }
                                }
                        }
@@ -138,7 +137,7 @@ class SimplePie_Misc
                foreach ($element['attribs'] as $key => $value)
                {
                        $key = strtolower($key);
-                       $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
+                       $full .= " $key=\"" . htmlspecialchars($value['data'], ENT_COMPAT, 'UTF-8') . '"';
                }
                if ($element['self_closing'])
                {
@@ -224,6 +223,23 @@ class SimplePie_Misc
                }
        }
 
+       public static function array_merge_recursive($array1, $array2)
+       {
+               foreach ($array2 as $key => $value)
+               {
+                       if (is_array($value))
+                       {
+                               $array1[$key] = SimplePie_Misc::array_merge_recursive($array1[$key], $value);
+                       }
+                       else
+                       {
+                               $array1[$key] = $value;
+                       }            
+               }
+               
+               return $array1;
+       }
+
        public static function parse_url($url)
        {
                $iri = new SimplePie_IRI($url);
index da80d8a..47658af 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index d51f500..a415ba6 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -173,7 +172,7 @@ class SimplePie_Parse_Date
                'aug' => 8,
                'august' => 8,
                'sep' => 9,
-               'september' => 8,
+               'september' => 9,
                'oct' => 10,
                'october' => 10,
                'nov' => 11,
@@ -331,6 +330,7 @@ class SimplePie_Parse_Date
                'CCT' => 23400,
                'CDT' => -18000,
                'CEDT' => 7200,
+               'CEST' => 7200,
                'CET' => 3600,
                'CGST' => -7200,
                'CGT' => -10800,
@@ -720,7 +720,7 @@ class SimplePie_Parse_Date
                {
                        $output .= substr($string, $position, $pos - $position);
                        $position = $pos + 1;
-                       if ($string[$pos - 1] !== '\\')
+                       if ($pos === 0 || $string[$pos - 1] !== '\\')
                        {
                                $depth++;
                                while ($depth && $position < $length)
index d698552..17139ab 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -75,8 +74,31 @@ class SimplePie_Parser
                $this->registry = $registry;
        }
 
-       public function parse(&$data, $encoding)
+       public function parse(&$data, $encoding, $url = '')
        {
+               if (function_exists('Mf2\parse')) {
+                       // Check for both h-feed and h-entry, as both a feed with no entries
+                       // and a list of entries without an h-feed wrapper are both valid.
+                       $position = 0;
+                       while ($position = strpos($data, 'h-feed', $position)) {
+                               $start = $position < 200 ? 0 : $position - 200;
+                               $check = substr($data, $start, 400);
+                               if (preg_match('/class="[^"]*h-feed/', $check)) {
+                                       return $this->parse_microformats($data, $url);
+                               }
+                               $position += 7;
+                       }
+                       $position = 0;
+                       while ($position = strpos($data, 'h-entry', $position)) {
+                               $start = $position < 200 ? 0 : $position - 200;
+                               $check = substr($data, $start, 400);
+                               if (preg_match('/class="[^"]*h-entry/', $check)) {
+                                       return $this->parse_microformats($data, $url);
+                               }
+                               $position += 7;
+                       }
+               }
+
                // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
                if (strtoupper($encoding) === 'US-ASCII')
                {
@@ -120,7 +142,7 @@ class SimplePie_Parser
                        if ($declaration->parse())
                        {
                                $data = substr($data, $pos + 2);
-                               $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
+                               $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' ."\n". $this->declare_html_entities() . $data;
                        }
                        else
                        {
@@ -404,4 +426,231 @@ class SimplePie_Parser
                }
                return $cache[$string];
        }
-}
+
+       private function parse_hcard($data, $category = false) {
+               $name = '';
+               $link = '';
+               // Check if h-card is set and pass that information on in the link.
+               if (isset($data['type']) && in_array('h-card', $data['type'])) {
+                       if (isset($data['properties']['name'][0])) {
+                               $name = $data['properties']['name'][0];
+                       }
+                       if (isset($data['properties']['url'][0])) {
+                               $link = $data['properties']['url'][0];
+                               if ($name === '') {
+                                       $name = $link;
+                               }
+                               else {
+                                       // can't have commas in categories.
+                                       $name = str_replace(',', '', $name);
+                               }
+                               $person_tag = $category ? '<span class="person-tag"></span>' : '';
+                               return '<a class="h-card" href="'.$link.'">'.$person_tag.$name.'</a>';
+                       }
+               }
+               return isset($data['value']) ? $data['value'] : '';
+       }
+
+       private function parse_microformats(&$data, $url) {
+               $feed_title = '';
+               $feed_author = NULL;
+               $author_cache = array();
+               $items = array();
+               $entries = array();
+               $mf = Mf2\parse($data, $url);
+               // First look for an h-feed.
+               $h_feed = array();
+               foreach ($mf['items'] as $mf_item) {
+                       if (in_array('h-feed', $mf_item['type'])) {
+                               $h_feed = $mf_item;
+                               break;
+                       }
+                       // Also look for an h-feed in the children of each top level item.
+                       if (!isset($mf_item['children'][0]['type'])) continue;
+                       if (in_array('h-feed', $mf_item['children'][0]['type'])) {
+                               $h_feed = $mf_item['children'][0];
+                               // In this case the parent of the h-feed may be an h-card, so use it as
+                               // the feed_author.
+                               if (in_array('h-card', $mf_item['type'])) $feed_author = $mf_item;
+                               break;
+                       }
+               }
+               if (isset($h_feed['children'])) {
+                       $entries = $h_feed['children'];
+                       // Also set the feed title and store author from the h-feed if available.
+                       if (isset($mf['items'][0]['properties']['name'][0])) {
+                               $feed_title = $mf['items'][0]['properties']['name'][0];
+                       }
+                       if (isset($mf['items'][0]['properties']['author'][0])) {
+                               $feed_author = $mf['items'][0]['properties']['author'][0];
+                       }
+               }
+               else {
+                       $entries = $mf['items'];
+               }
+               for ($i = 0; $i < count($entries); $i++) {
+                       $entry = $entries[$i];
+                       if (in_array('h-entry', $entry['type'])) {
+                               $item = array();
+                               $title = '';
+                               $description = '';
+                               if (isset($entry['properties']['url'][0])) {
+                                       $link = $entry['properties']['url'][0];
+                                       if (isset($link['value'])) $link = $link['value'];
+                                       $item['link'] = array(array('data' => $link));
+                               }
+                               if (isset($entry['properties']['uid'][0])) {
+                                       $guid = $entry['properties']['uid'][0];
+                                       if (isset($guid['value'])) $guid = $guid['value'];
+                                       $item['guid'] = array(array('data' => $guid));
+                               }
+                               if (isset($entry['properties']['name'][0])) {
+                                       $title = $entry['properties']['name'][0];
+                                       if (isset($title['value'])) $title = $title['value'];
+                                       $item['title'] = array(array('data' => $title));
+                               }
+                               if (isset($entry['properties']['author'][0]) || isset($feed_author)) {
+                                       // author is a special case, it can be plain text or an h-card array.
+                                       // If it's plain text it can also be a url that should be followed to
+                                       // get the actual h-card.
+                                       $author = isset($entry['properties']['author'][0]) ?
+                                               $entry['properties']['author'][0] : $feed_author;
+                                       if (!is_string($author)) {
+                                               $author = $this->parse_hcard($author);
+                                       }
+                                       else if (strpos($author, 'http') === 0) {
+                                               if (isset($author_cache[$author])) {
+                                                       $author = $author_cache[$author];
+                                               }
+                                               else {
+                                                       $mf = Mf2\fetch($author);
+                                                       foreach ($mf['items'] as $hcard) {
+                                                               // Only interested in an h-card by itself in this case.
+                                                               if (!in_array('h-card', $hcard['type'])) {
+                                                                       continue;
+                                                               }
+                                                               // It must have a url property matching what we fetched.
+                                                               if (!isset($hcard['properties']['url']) ||
+                                                                               !(in_array($author, $hcard['properties']['url']))) {
+                                                                       continue;
+                                                               }
+                                                               // Save parse_hcard the trouble of finding the correct url.
+                                                               $hcard['properties']['url'][0] = $author;
+                                                               // Cache this h-card for the next h-entry to check.
+                                                               $author_cache[$author] = $this->parse_hcard($hcard);
+                                                               $author = $author_cache[$author];
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                                       $item['author'] = array(array('data' => $author));
+                               }
+                               if (isset($entry['properties']['photo'][0])) {
+                                       // If a photo is also in content, don't need to add it again here.
+                                       $content = '';
+                                       if (isset($entry['properties']['content'][0]['html'])) {
+                                               $content = $entry['properties']['content'][0]['html'];
+                                       }
+                                       $photo_list = array();
+                                       for ($j = 0; $j < count($entry['properties']['photo']); $j++) {
+                                               $photo = $entry['properties']['photo'][$j];
+                                               if (strpos($content, $photo) === false) {
+                                                       $photo_list[] = $photo;
+                                               }
+                                       }
+                                       // When there's more than one photo show the first and use a lightbox.
+                                       $count = count($photo_list);
+                                       if ($count > 1) {
+                                               $description = '<p>';
+                                               for ($j = 0; $j < $count; $j++) {
+                                                       $hidden = $j === 0 ? '' : 'class="hidden" ';
+                                                       $description .= '<a href="'.$photo_list[$j].'" '.$hidden.
+                                                               'data-lightbox="image-set-'.$i.'">'.
+                                                               '<img src="'.$photo_list[$j].'"></a>';
+                                               }
+                                               $description .= '<br><b>'.$count.' photos</b></p>';
+                                       }
+                                       else if ($count == 1) {
+                                               $description = '<p><img src="'.$photo_list[0].'"></p>';
+                                       }
+                               }
+                               if (isset($entry['properties']['content'][0]['html'])) {
+                                       // e-content['value'] is the same as p-name when they are on the same
+                                       // element. Use this to replace title with a strip_tags version so
+                                       // that alt text from images is not included in the title.
+                                       if ($entry['properties']['content'][0]['value'] === $title) {
+                                               $title = strip_tags($entry['properties']['content'][0]['html']);
+                                               $item['title'] = array(array('data' => $title));
+                                       }
+                                       $description .= $entry['properties']['content'][0]['html'];
+                                       if (isset($entry['properties']['in-reply-to'][0]['value'])) {
+                                               $in_reply_to = $entry['properties']['in-reply-to'][0]['value'];
+                                               $description .= '<p><span class="in-reply-to"></span> '.
+                                                       '<a href="'.$in_reply_to.'">'.$in_reply_to.'</a><p>';
+                                       }
+                                       $item['description'] = array(array('data' => $description));
+                               }
+                               if (isset($entry['properties']['category'])) {
+                                       $category_csv = '';
+                                       // Categories can also contain h-cards.
+                                       foreach ($entry['properties']['category'] as $category) {
+                                               if ($category_csv !== '') $category_csv .= ', ';
+                                               if (is_string($category)) {
+                                                       // Can't have commas in categories.
+                                                       $category_csv .= str_replace(',', '', $category);
+                                               }
+                                               else {
+                                                       $category_csv .= $this->parse_hcard($category, true);
+                                               }
+                                       }
+                                       $item['category'] = array(array('data' => $category_csv));
+                               }
+                               if (isset($entry['properties']['published'][0])) {
+                                       $timestamp = strtotime($entry['properties']['published'][0]);
+                                       $pub_date = date('F j Y g:ia', $timestamp).' GMT';
+                                       $item['pubDate'] = array(array('data' => $pub_date));
+                               }
+                               // The title and description are set to the empty string to represent
+                               // a deleted item (which also makes it an invalid rss item).
+                               if (isset($entry['properties']['deleted'][0])) {
+                                       $item['title'] = array(array('data' => ''));
+                                       $item['description'] = array(array('data' => ''));
+                               }
+                               $items[] = array('child' => array('' => $item));
+                       }
+               }
+               // Mimic RSS data format when storing microformats.
+               $link = array(array('data' => $url));
+               $image = '';
+               if (!is_string($feed_author) &&
+                               isset($feed_author['properties']['photo'][0])) {
+                       $image = array(array('child' => array('' => array('url' =>
+                               array(array('data' => $feed_author['properties']['photo'][0]))))));
+               }
+               // Use the a name given for the h-feed, or get the title from the html.
+               if ($feed_title !== '') {
+                       $feed_title = array(array('data' => htmlspecialchars($feed_title)));
+               }
+               else if ($position = strpos($data, '<title>')) {
+                       $start = $position < 200 ? 0 : $position - 200;
+                       $check = substr($data, $start, 400);
+                       $matches = array();
+                       if (preg_match('/<title>(.+)<\/title>/', $check, $matches)) {
+                               $feed_title = array(array('data' => htmlspecialchars($matches[1])));
+                       }
+               }
+               $channel = array('channel' => array(array('child' => array('' =>
+                       array('link' => $link, 'image' => $image, 'title' => $feed_title,
+                             'item' => $items)))));
+               $rss = array(array('attribs' => array('' => array('version' => '2.0')),
+                                  'child' => array('' => $channel)));
+               $this->data = array('child' => array('' => array('rss' => $rss)));
+               return true;
+       }
+
+       private function declare_html_entities() {
+               // This is required because the RSS specification says that entity-encoded
+               // html is allowed, but the xml specification says they must be declared.
+               return '<!DOCTYPE html [ <!ENTITY nbsp "&#x00A0;"> <!ENTITY iexcl "&#x00A1;"> <!ENTITY cent "&#x00A2;"> <!ENTITY pound "&#x00A3;"> <!ENTITY curren "&#x00A4;"> <!ENTITY yen "&#x00A5;"> <!ENTITY brvbar "&#x00A6;"> <!ENTITY sect "&#x00A7;"> <!ENTITY uml "&#x00A8;"> <!ENTITY copy "&#x00A9;"> <!ENTITY ordf "&#x00AA;"> <!ENTITY laquo "&#x00AB;"> <!ENTITY not "&#x00AC;"> <!ENTITY shy "&#x00AD;"> <!ENTITY reg "&#x00AE;"> <!ENTITY macr "&#x00AF;"> <!ENTITY deg "&#x00B0;"> <!ENTITY plusmn "&#x00B1;"> <!ENTITY sup2 "&#x00B2;"> <!ENTITY sup3 "&#x00B3;"> <!ENTITY acute "&#x00B4;"> <!ENTITY micro "&#x00B5;"> <!ENTITY para "&#x00B6;"> <!ENTITY middot "&#x00B7;"> <!ENTITY cedil "&#x00B8;"> <!ENTITY sup1 "&#x00B9;"> <!ENTITY ordm "&#x00BA;"> <!ENTITY raquo "&#x00BB;"> <!ENTITY frac14 "&#x00BC;"> <!ENTITY frac12 "&#x00BD;"> <!ENTITY frac34 "&#x00BE;"> <!ENTITY iquest "&#x00BF;"> <!ENTITY Agrave "&#x00C0;"> <!ENTITY Aacute "&#x00C1;"> <!ENTITY Acirc "&#x00C2;"> <!ENTITY Atilde "&#x00C3;"> <!ENTITY Auml "&#x00C4;"> <!ENTITY Aring "&#x00C5;"> <!ENTITY AElig "&#x00C6;"> <!ENTITY Ccedil "&#x00C7;"> <!ENTITY Egrave "&#x00C8;"> <!ENTITY Eacute "&#x00C9;"> <!ENTITY Ecirc "&#x00CA;"> <!ENTITY Euml "&#x00CB;"> <!ENTITY Igrave "&#x00CC;"> <!ENTITY Iacute "&#x00CD;"> <!ENTITY Icirc "&#x00CE;"> <!ENTITY Iuml "&#x00CF;"> <!ENTITY ETH "&#x00D0;"> <!ENTITY Ntilde "&#x00D1;"> <!ENTITY Ograve "&#x00D2;"> <!ENTITY Oacute "&#x00D3;"> <!ENTITY Ocirc "&#x00D4;"> <!ENTITY Otilde "&#x00D5;"> <!ENTITY Ouml "&#x00D6;"> <!ENTITY times "&#x00D7;"> <!ENTITY Oslash "&#x00D8;"> <!ENTITY Ugrave "&#x00D9;"> <!ENTITY Uacute "&#x00DA;"> <!ENTITY Ucirc "&#x00DB;"> <!ENTITY Uuml "&#x00DC;"> <!ENTITY Yacute "&#x00DD;"> <!ENTITY THORN "&#x00DE;"> <!ENTITY szlig "&#x00DF;"> <!ENTITY agrave "&#x00E0;"> <!ENTITY aacute "&#x00E1;"> <!ENTITY acirc "&#x00E2;"> <!ENTITY atilde "&#x00E3;"> <!ENTITY auml "&#x00E4;"> <!ENTITY aring "&#x00E5;"> <!ENTITY aelig "&#x00E6;"> <!ENTITY ccedil "&#x00E7;"> <!ENTITY egrave "&#x00E8;"> <!ENTITY eacute "&#x00E9;"> <!ENTITY ecirc "&#x00EA;"> <!ENTITY euml "&#x00EB;"> <!ENTITY igrave "&#x00EC;"> <!ENTITY iacute "&#x00ED;"> <!ENTITY icirc "&#x00EE;"> <!ENTITY iuml "&#x00EF;"> <!ENTITY eth "&#x00F0;"> <!ENTITY ntilde "&#x00F1;"> <!ENTITY ograve "&#x00F2;"> <!ENTITY oacute "&#x00F3;"> <!ENTITY ocirc "&#x00F4;"> <!ENTITY otilde "&#x00F5;"> <!ENTITY ouml "&#x00F6;"> <!ENTITY divide "&#x00F7;"> <!ENTITY oslash "&#x00F8;"> <!ENTITY ugrave "&#x00F9;"> <!ENTITY uacute "&#x00FA;"> <!ENTITY ucirc "&#x00FB;"> <!ENTITY uuml "&#x00FC;"> <!ENTITY yacute "&#x00FD;"> <!ENTITY thorn "&#x00FE;"> <!ENTITY yuml "&#x00FF;"> <!ENTITY OElig "&#x0152;"> <!ENTITY oelig "&#x0153;"> <!ENTITY Scaron "&#x0160;"> <!ENTITY scaron "&#x0161;"> <!ENTITY Yuml "&#x0178;"> <!ENTITY fnof "&#x0192;"> <!ENTITY circ "&#x02C6;"> <!ENTITY tilde "&#x02DC;"> <!ENTITY Alpha "&#x0391;"> <!ENTITY Beta "&#x0392;"> <!ENTITY Gamma "&#x0393;"> <!ENTITY Epsilon "&#x0395;"> <!ENTITY Zeta "&#x0396;"> <!ENTITY Eta "&#x0397;"> <!ENTITY Theta "&#x0398;"> <!ENTITY Iota "&#x0399;"> <!ENTITY Kappa "&#x039A;"> <!ENTITY Lambda "&#x039B;"> <!ENTITY Mu "&#x039C;"> <!ENTITY Nu "&#x039D;"> <!ENTITY Xi "&#x039E;"> <!ENTITY Omicron "&#x039F;"> <!ENTITY Pi "&#x03A0;"> <!ENTITY Rho "&#x03A1;"> <!ENTITY Sigma "&#x03A3;"> <!ENTITY Tau "&#x03A4;"> <!ENTITY Upsilon "&#x03A5;"> <!ENTITY Phi "&#x03A6;"> <!ENTITY Chi "&#x03A7;"> <!ENTITY Psi "&#x03A8;"> <!ENTITY Omega "&#x03A9;"> <!ENTITY alpha "&#x03B1;"> <!ENTITY beta "&#x03B2;"> <!ENTITY gamma "&#x03B3;"> <!ENTITY delta "&#x03B4;"> <!ENTITY epsilon "&#x03B5;"> <!ENTITY zeta "&#x03B6;"> <!ENTITY eta "&#x03B7;"> <!ENTITY theta "&#x03B8;"> <!ENTITY iota "&#x03B9;"> <!ENTITY kappa "&#x03BA;"> <!ENTITY lambda "&#x03BB;"> <!ENTITY mu "&#x03BC;"> <!ENTITY nu "&#x03BD;"> <!ENTITY xi "&#x03BE;"> <!ENTITY omicron "&#x03BF;"> <!ENTITY pi "&#x03C0;"> <!ENTITY rho "&#x03C1;"> <!ENTITY sigmaf "&#x03C2;"> <!ENTITY sigma "&#x03C3;"> <!ENTITY tau "&#x03C4;"> <!ENTITY upsilon "&#x03C5;"> <!ENTITY phi "&#x03C6;"> <!ENTITY chi "&#x03C7;"> <!ENTITY psi "&#x03C8;"> <!ENTITY omega "&#x03C9;"> <!ENTITY thetasym "&#x03D1;"> <!ENTITY upsih "&#x03D2;"> <!ENTITY piv "&#x03D6;"> <!ENTITY ensp "&#x2002;"> <!ENTITY emsp "&#x2003;"> <!ENTITY thinsp "&#x2009;"> <!ENTITY zwnj "&#x200C;"> <!ENTITY zwj "&#x200D;"> <!ENTITY lrm "&#x200E;"> <!ENTITY rlm "&#x200F;"> <!ENTITY ndash "&#x2013;"> <!ENTITY mdash "&#x2014;"> <!ENTITY lsquo "&#x2018;"> <!ENTITY rsquo "&#x2019;"> <!ENTITY sbquo "&#x201A;"> <!ENTITY ldquo "&#x201C;"> <!ENTITY rdquo "&#x201D;"> <!ENTITY bdquo "&#x201E;"> <!ENTITY dagger "&#x2020;"> <!ENTITY Dagger "&#x2021;"> <!ENTITY bull "&#x2022;"> <!ENTITY hellip "&#x2026;"> <!ENTITY permil "&#x2030;"> <!ENTITY prime "&#x2032;"> <!ENTITY Prime "&#x2033;"> <!ENTITY lsaquo "&#x2039;"> <!ENTITY rsaquo "&#x203A;"> <!ENTITY oline "&#x203E;"> <!ENTITY frasl "&#x2044;"> <!ENTITY euro "&#x20AC;"> <!ENTITY image "&#x2111;"> <!ENTITY weierp "&#x2118;"> <!ENTITY real "&#x211C;"> <!ENTITY trade "&#x2122;"> <!ENTITY alefsym "&#x2135;"> <!ENTITY larr "&#x2190;"> <!ENTITY uarr "&#x2191;"> <!ENTITY rarr "&#x2192;"> <!ENTITY darr "&#x2193;"> <!ENTITY harr "&#x2194;"> <!ENTITY crarr "&#x21B5;"> <!ENTITY lArr "&#x21D0;"> <!ENTITY uArr "&#x21D1;"> <!ENTITY rArr "&#x21D2;"> <!ENTITY dArr "&#x21D3;"> <!ENTITY hArr "&#x21D4;"> <!ENTITY forall "&#x2200;"> <!ENTITY part "&#x2202;"> <!ENTITY exist "&#x2203;"> <!ENTITY empty "&#x2205;"> <!ENTITY nabla "&#x2207;"> <!ENTITY isin "&#x2208;"> <!ENTITY notin "&#x2209;"> <!ENTITY ni "&#x220B;"> <!ENTITY prod "&#x220F;"> <!ENTITY sum "&#x2211;"> <!ENTITY minus "&#x2212;"> <!ENTITY lowast "&#x2217;"> <!ENTITY radic "&#x221A;"> <!ENTITY prop "&#x221D;"> <!ENTITY infin "&#x221E;"> <!ENTITY ang "&#x2220;"> <!ENTITY and "&#x2227;"> <!ENTITY or "&#x2228;"> <!ENTITY cap "&#x2229;"> <!ENTITY cup "&#x222A;"> <!ENTITY int "&#x222B;"> <!ENTITY there4 "&#x2234;"> <!ENTITY sim "&#x223C;"> <!ENTITY cong "&#x2245;"> <!ENTITY asymp "&#x2248;"> <!ENTITY ne "&#x2260;"> <!ENTITY equiv "&#x2261;"> <!ENTITY le "&#x2264;"> <!ENTITY ge "&#x2265;"> <!ENTITY sub "&#x2282;"> <!ENTITY sup "&#x2283;"> <!ENTITY nsub "&#x2284;"> <!ENTITY sube "&#x2286;"> <!ENTITY supe "&#x2287;"> <!ENTITY oplus "&#x2295;"> <!ENTITY otimes "&#x2297;"> <!ENTITY perp "&#x22A5;"> <!ENTITY sdot "&#x22C5;"> <!ENTITY lceil "&#x2308;"> <!ENTITY rceil "&#x2309;"> <!ENTITY lfloor "&#x230A;"> <!ENTITY rfloor "&#x230B;"> <!ENTITY lang "&#x2329;"> <!ENTITY rang "&#x232A;"> <!ENTITY loz "&#x25CA;"> <!ENTITY spades "&#x2660;"> <!ENTITY clubs "&#x2663;"> <!ENTITY hearts "&#x2665;"> <!ENTITY diams "&#x2666;"> ]>';
+       }
+}
\ No newline at end of file
index 8689e5d..eaf5708 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
old mode 100644 (file)
new mode 100755 (executable)
index 1072cde..e0909bb
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -113,7 +112,7 @@ class SimplePie_Registry
         */
        public function register($type, $class, $legacy = false)
        {
-               if (!is_subclass_of($class, $this->default[$type]))
+               if (!@is_subclass_of($class, $this->default[$type]))
                {
                        return false;
                }
@@ -222,4 +221,4 @@ class SimplePie_Registry
                $result = call_user_func_array(array($class, $method), $parameters);
                return $result;
        }
-}
\ No newline at end of file
+}
index 4ba371b..001a5cd 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index 6810cc4..aeb7039 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
@@ -61,7 +60,8 @@ class SimplePie_Sanitize
        var $image_handler = '';
        var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
        var $encode_instead_of_strip = false;
-       var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
+       var $strip_attributes = array('bgsound', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
+       var $add_attributes = array('audio' => array('preload' => 'none'), 'iframe' => array('sandbox' => 'allow-scripts allow-same-origin'), 'video' => array('preload' => 'none'));
        var $strip_comments = false;
        var $output_encoding = 'UTF-8';
        var $enable_cache = true;
@@ -160,7 +160,7 @@ class SimplePie_Sanitize
                $this->encode_instead_of_strip = (bool) $encode;
        }
 
-       public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
+       public function strip_attributes($attribs = array('bgsound', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
        {
                if ($attribs)
                {
@@ -179,6 +179,25 @@ class SimplePie_Sanitize
                }
        }
 
+       public function add_attributes($attribs = array('audio' => array('preload' => 'none'), 'iframe' => array('sandbox' => 'allow-scripts allow-same-origin'), 'video' => array('preload' => 'none')))
+       {
+               if ($attribs)
+               {
+                       if (is_array($attribs))
+                       {
+                               $this->add_attributes = $attribs;
+                       }
+                       else
+                       {
+                               $this->add_attributes = explode(',', $attribs);
+                       }
+               }
+               else
+               {
+                       $this->add_attributes = false;
+               }
+       }
+
        public function strip_comments($strip = false)
        {
                $this->strip_comments = (bool) $strip;
@@ -247,18 +266,28 @@ class SimplePie_Sanitize
                        if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
                        {
 
+                               if (!class_exists('DOMDocument'))
+                               {
+                                       throw new SimplePie_Exception('DOMDocument not found, unable to use sanitizer');
+                               }
                                $document = new DOMDocument();
                                $document->encoding = 'UTF-8';
+
+                               // See https://github.com/simplepie/simplepie/issues/334
+                               $unique_tag = '#'.uniqid().'#';
+                               $data = trim($unique_tag . $data . $unique_tag);
+
                                $data = $this->preprocess($data, $type);
 
                                set_error_handler(array('SimplePie_Misc', 'silence_errors'));
                                $document->loadHTML($data);
                                restore_error_handler();
 
+                               $xpath = new DOMXPath($document);
+
                                // Strip comments
                                if ($this->strip_comments)
                                {
-                                       $xpath = new DOMXPath($document);
                                        $comments = $xpath->query('//comment()');
 
                                        foreach ($comments as $comment)
@@ -274,7 +303,7 @@ class SimplePie_Sanitize
                                {
                                        foreach ($this->strip_htmltags as $tag)
                                        {
-                                               $this->strip_tag($tag, $document, $type);
+                                               $this->strip_tag($tag, $document, $xpath, $type);
                                        }
                                }
 
@@ -282,7 +311,15 @@ class SimplePie_Sanitize
                                {
                                        foreach ($this->strip_attributes as $attrib)
                                        {
-                                               $this->strip_attr($attrib, $document);
+                                               $this->strip_attr($attrib, $xpath);
+                                       }
+                               }
+
+                               if ($this->add_attributes)
+                               {
+                                       foreach ($this->add_attributes as $tag => $valuePairs)
+                                       {
+                                               $this->add_attr($tag, $valuePairs, $document);
                                        }
                                }
 
@@ -310,7 +347,7 @@ class SimplePie_Sanitize
                                                        }
                                                        else
                                                        {
-                                                               $file = $this->registry->create('File', array($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen));
+                                                               $file = $this->registry->create('File', array($img->getAttribute('src'), $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen));
                                                                $headers = $file->headers;
 
                                                                if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
@@ -329,19 +366,11 @@ class SimplePie_Sanitize
                                        }
                                }
 
-                               // Remove the DOCTYPE
-                               // Seems to cause segfaulting if we don't do this
-                               if ($document->firstChild instanceof DOMDocumentType)
-                               {
-                                       $document->removeChild($document->firstChild);
-                               }
-
-                               // Move everything from the body to the root
-                               $real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0);
-                               $document->replaceChild($real_body, $document->firstChild);
-
                                // Finally, convert to a HTML string
                                $data = trim($document->saveHTML());
+                               $result = explode($unique_tag, $data);
+                               // The tags may not be found again if there was invalid markup.
+                               $data = count($result) === 3 ? $result[1] : '';
 
                                if ($this->remove_div)
                                {
@@ -379,6 +408,7 @@ class SimplePie_Sanitize
        protected function preprocess($html, $type)
        {
                $ret = '';
+               $html = preg_replace('%</?(?:html|body)[^>]*?'.'>%is', '', $html);
                if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML)
                {
                        // Atom XHTML constructs are wrapped with a div by default
@@ -451,9 +481,8 @@ class SimplePie_Sanitize
                }
        }
 
-       protected function strip_tag($tag, $document, $type)
+       protected function strip_tag($tag, $document, $xpath, $type)
        {
-               $xpath = new DOMXPath($document);
                $elements = $xpath->query('body//' . $tag);
                if ($this->encode_instead_of_strip)
                {
@@ -536,9 +565,8 @@ class SimplePie_Sanitize
                }
        }
 
-       protected function strip_attr($attrib, $document)
+       protected function strip_attr($attrib, $xpath)
        {
-               $xpath = new DOMXPath($document);
                $elements = $xpath->query('//*[@' . $attrib . ']');
 
                foreach ($elements as $element)
@@ -546,4 +574,16 @@ class SimplePie_Sanitize
                        $element->removeAttribute($attrib);
                }
        }
+
+       protected function add_attr($tag, $valuePairs, $document)
+       {
+               $elements = $document->getElementsByTagName($tag);
+               foreach ($elements as $element)
+               {
+                       foreach ($valuePairs as $attrib => $value)
+                       {
+                               $element->setAttribute($attrib, $value);
+                       }
+               }
+       }
 }
index 51d8e6c..1a66a39 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index aec19f1..99e7516 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue
index 52e024e..0e8bc8f 100644 (file)
@@ -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-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
@@ -33,8 +33,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @package SimplePie
- * @version 1.3.1
- * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  * @author Ryan Parman
  * @author Geoffrey Sneddon
  * @author Ryan McCue