Your IP : 216.73.216.248


Current Path : /home/digilove/www/41423/
Upload File :
Current File : /home/digilove/www/41423/Feed.tar

Parser/Rss/ItunesRssParser.php000064400000002651152345403320012401 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Feed\Parser\Rss;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Feed\Feed;
use Joomla\CMS\Feed\FeedEntry;
use Joomla\CMS\Feed\Parser\NamespaceParserInterface;

/**
 * RSS Feed Parser Namespace handler for iTunes.
 *
 * @link   https://itunespartner.apple.com/en/podcasts/overview
 * @since  3.1.4
 */
class ItunesRssParser implements NamespaceParserInterface
{
	/**
	 * Method to handle an element for the feed given that the itunes namespace is present.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	public function processElementForFeed(Feed $feed, \SimpleXMLElement $el)
	{
		return;
	}

	/**
	 * Method to handle the feed entry element for the feed given that the itunes namespace is present.
	 *
	 * @param   FeedEntry          $entry  The FeedEntry object being built from the parsed feed entry.
	 * @param   \SimpleXMLElement  $el     The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	public function processElementForFeedEntry(FeedEntry $entry, \SimpleXMLElement $el)
	{
		return;
	}
}
Parser/Rss/MediaRssParser.php000064400000002626152345403320012153 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Feed\Parser\Rss;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Feed\Feed;
use Joomla\CMS\Feed\FeedEntry;
use Joomla\CMS\Feed\Parser\NamespaceParserInterface;

/**
 * RSS Feed Parser Namespace handler for MediaRSS.
 *
 * @link   http://video.search.yahoo.com/mrss
 * @since  3.1.4
 */
class MediaRssParser implements NamespaceParserInterface
{
	/**
	 * Method to handle an element for the feed given that the media namespace is present.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	public function processElementForFeed(Feed $feed, \SimpleXMLElement $el)
	{
		return;
	}

	/**
	 * Method to handle the feed entry element for the feed given that the media namespace is present.
	 *
	 * @param   FeedEntry          $entry  The FeedEntry object being built from the parsed feed entry.
	 * @param   \SimpleXMLElement  $el     The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	public function processElementForFeedEntry(FeedEntry $entry, \SimpleXMLElement $el)
	{
		return;
	}
}
Parser/AtomParser.php000064400000015756152345403320010605 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Feed\Parser;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Feed\Feed;
use Joomla\CMS\Feed\FeedEntry;
use Joomla\CMS\Feed\FeedLink;
use Joomla\CMS\Feed\FeedParser;

/**
 * ATOM Feed Parser class.
 *
 * @link   http://www.atomenabled.org/developers/syndication/
 * @since  3.1.4
 */
class AtomParser extends FeedParser
{
	/**
	 * @var    string  The feed format version.
	 * @since  3.1.4
	 */
	protected $version;

	/**
	 * Method to handle the `<author>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleAuthor(Feed $feed, \SimpleXMLElement $el)
	{
		// Set the author information from the XML element.
		$feed->setAuthor(
			$this->inputFilter->clean((string) $el->name, 'html'),
			filter_var((string) $el->email, FILTER_VALIDATE_EMAIL),
			filter_var((string) $el->uri, FILTER_VALIDATE_URL)
		);
	}

	/**
	 * Method to handle the `<contributor>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleContributor(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->addContributor(
			$this->inputFilter->clean((string) $el->name, 'html'),
			filter_var((string) $el->email, FILTER_VALIDATE_EMAIL),
			filter_var((string) $el->uri, FILTER_VALIDATE_URL)
		);
	}

	/**
	 * Method to handle the `<generator>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleGenerator(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->generator = $this->inputFilter->clean((string) $el, 'html');
	}

	/**
	 * Method to handle the `<id>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleId(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->uri = (string) $el;
	}

	/**
	 * Method to handle the `<link>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleLink(Feed $feed, \SimpleXMLElement $el)
	{
		$link = new FeedLink;
		$link->uri      = (string) $el['href'];
		$link->language = (string) $el['hreflang'];
		$link->length   = (int) $el['length'];
		$link->relation = (string) $el['rel'];
		$link->title    = $this->inputFilter->clean((string) $el['title'], 'html');
		$link->type     = (string) $el['type'];

		$feed->link = $link;
	}

	/**
	 * Method to handle the `<rights>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleRights(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->copyright = $this->inputFilter->clean((string) $el, 'html');
	}

	/**
	 * Method to handle the `<subtitle>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleSubtitle(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->description = $this->inputFilter->clean((string) $el, 'html');
	}

	/**
	 * Method to handle the `<title>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleTitle(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->title = $this->inputFilter->clean((string) $el, 'html');
	}

	/**
	 * Method to handle the `<updated>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleUpdated(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->updatedDate = $this->inputFilter->clean((string) $el, 'html');
	}

	/**
	 * Method to initialise the feed for parsing.  Here we detect the version and advance the stream
	 * reader so that it is ready to parse feed elements.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function initialise()
	{
		// Read the version attribute.
		$this->version = ($this->stream->getAttribute('version') == '0.3') ? '0.3' : '1.0';

		// We want to move forward to the first element after the root element.
		$this->moveToNextElement();
	}

	/**
	 * Method to handle a `<entry>` element for the feed.
	 *
	 * @param   FeedEntry          $entry  The FeedEntry object being built from the parsed feed entry.
	 * @param   \SimpleXMLElement  $el     The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function processFeedEntry(FeedEntry $entry, \SimpleXMLElement $el)
	{
		$entry->uri         = (string) $el->id;
		$entry->title       = $this->inputFilter->clean((string) $el->title, 'html');
		$entry->updatedDate = $this->inputFilter->clean((string) $el->updated, 'html');
		$entry->content     = $this->inputFilter->clean((string) $el->summary, 'html');

		if (!$entry->content)
		{
			$entry->content = $this->inputFilter->clean((string) $el->content, 'html');
		}

		if (filter_var($entry->uri, FILTER_VALIDATE_URL) === false && !is_null($el->link) && $el->link)
		{
			$link = $el->link;

			if (is_array($link))
			{
				$link = $this->bestLinkForUri($link);
			}

			$uri = (string) $link['href'];

			if ($uri)
			{
				$entry->uri = $uri;
			}
		}
	}

	/**
	 * If there is more than one <link> in the feed entry, find the most appropriate one and return it.
	 *
	 * @param   array  $links  Array of <link> elements from the feed entry.
	 *
	 * @return  \SimpleXMLElement
	 */
	private function bestLinkForUri(array $links)
	{
		$linkPrefs = array('', 'self', 'alternate');

		foreach ($linkPrefs as $pref)
		{
			foreach ($links as $link)
			{
				$rel = (string) $link['rel'];

				if ($rel === $pref)
				{
					return $link;
				}
			}
		}

		return array_shift($links);
	}
}
Parser/NamespaceParserInterface.php000064400000002345152345403320013410 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Feed\Parser;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Feed\Feed;
use Joomla\CMS\Feed\FeedEntry;

/**
 * Feed Namespace interface.
 *
 * @since  3.1.4
 */
interface NamespaceParserInterface
{
	/**
	 * Method to handle an element for the feed given that a certain namespace is present.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	public function processElementForFeed(Feed $feed, \SimpleXMLElement $el);

	/**
	 * Method to handle the feed entry element for the feed given that a certain namespace is present.
	 *
	 * @param   FeedEntry          $entry  The FeedEntry object being built from the parsed feed entry.
	 * @param   \SimpleXMLElement  $el     The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	public function processElementForFeedEntry(FeedEntry $entry, \SimpleXMLElement $el);
}
Parser/RssParser.php000064400000027550152345403320010447 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Feed\Parser;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Feed\Feed;
use Joomla\CMS\Feed\FeedEntry;
use Joomla\CMS\Feed\FeedLink;
use Joomla\CMS\Feed\FeedParser;
use Joomla\CMS\Feed\FeedPerson;

/**
 * RSS Feed Parser class.
 *
 * @link   http://cyber.law.harvard.edu/rss/rss.html
 * @since  3.1.4
 */
class RssParser extends FeedParser
{
	/**
	 * @var    string  The feed element name for the entry elements.
	 * @since  3.1.4
	 */
	protected $entryElementName = 'item';

	/**
	 * @var    string  The feed format version.
	 * @since  3.1.4
	 */
	protected $version;

	/**
	 * Method to handle the `<category>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleCategory(Feed $feed, \SimpleXMLElement $el)
	{
		// Get the data from the element.
		$domain    = (string) $el['domain'];
		$category  = $this->inputFilter->clean((string) $el, 'html');

		$feed->addCategory($category, $domain);
	}

	/**
	 * Method to handle the `<cloud>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleCloud(Feed $feed, \SimpleXMLElement $el)
	{
		$cloud = new \stdClass;
		$cloud->domain            = (string) $el['domain'];
		$cloud->port              = (string) $el['port'];
		$cloud->path              = (string) $el['path'];
		$cloud->protocol          = (string) $el['protocol'];
		$cloud->registerProcedure = (string) $el['registerProcedure'];

		$feed->cloud = $cloud;
	}

	/**
	 * Method to handle the `<copyright>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleCopyright(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->copyright = $this->inputFilter->clean((string) $el, 'html');
	}

	/**
	 * Method to handle the `<description>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleDescription(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->description = $this->inputFilter->clean((string) $el, 'html');
	}

	/**
	 * Method to handle the `<generator>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleGenerator(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->generator = $this->inputFilter->clean((string) $el, 'html');
	}

	/**
	 * Method to handle the `<image>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleImage(Feed $feed, \SimpleXMLElement $el)
	{
		// Create a feed link object for the image.
		$image = new FeedLink(
			(string) $el->url,
			null,
			'logo',
			null,
			$this->inputFilter->clean((string) $el->title, 'html')
		);

		// Populate extra fields if they exist.
		$image->link         = (string) filter_var($el->link, FILTER_VALIDATE_URL);
		$image->description  = $this->inputFilter->clean((string) $el->description, 'html');
		$image->height       = (string) $el->height;
		$image->width        = (string) $el->width;

		$feed->image = $image;
	}

	/**
	 * Method to handle the `<language>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleLanguage(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->language = $this->inputFilter->clean((string) $el, 'html');
	}

	/**
	 * Method to handle the `<lastBuildDate>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleLastBuildDate(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->updatedDate = $this->inputFilter->clean((string) $el, 'html');
	}

	/**
	 * Method to handle the `<link>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleLink(Feed $feed, \SimpleXMLElement $el)
	{
		$link = new FeedLink;
		$link->uri = (string) $el['href'];
		$feed->link = $link;
	}

	/**
	 * Method to handle the `<managingEditor>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleManagingEditor(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->author = $this->processPerson((string) $el);
	}

	/**
	 * Method to handle the `<skipDays>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleSkipDays(Feed $feed, \SimpleXMLElement $el)
	{
		// Initialise the array.
		$days = array();

		// Add all of the day values from the feed to the array.
		foreach ($el->day as $day)
		{
			$days[] = (string) $day;
		}

		$feed->skipDays = $days;
	}

	/**
	 * Method to handle the `<skipHours>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleSkipHours(Feed $feed, \SimpleXMLElement $el)
	{
		// Initialise the array.
		$hours = array();

		// Add all of the day values from the feed to the array.
		foreach ($el->hour as $hour)
		{
			$hours[] = (int) $hour;
		}

		$feed->skipHours = $hours;
	}

	/**
	 * Method to handle the `<pubDate>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handlePubDate(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->publishedDate = $this->inputFilter->clean((string) $el, 'html');
	}

	/**
	 * Method to handle the `<title>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleTitle(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->title = $this->inputFilter->clean((string) $el, 'html');
	}

	/**
	 * Method to handle the `<ttl>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleTtl(Feed $feed, \SimpleXMLElement $el)
	{
		$feed->ttl = (integer) $this->inputFilter->clean((string) $el, 'int');
	}

	/**
	 * Method to handle the `<webmaster>` element for the feed.
	 *
	 * @param   Feed               $feed  The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el    The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function handleWebmaster(Feed $feed, \SimpleXMLElement $el)
	{
		// Get the tag contents and split it over the first space.
		$tmp = (string) $el;
		$tmp = explode(' ', $tmp, 2);

		// This is really cheap parsing.  Probably need to create a method to do this more robustly.
		$name = null;

		if (isset($tmp[1]))
		{
			$name = trim(
				$this->inputFilter->clean($tmp[1], 'html'),
				' ()'
			);
		}

		$email = trim(
			filter_var((string) $tmp[0], FILTER_VALIDATE_EMAIL)
		);

		$feed->addContributor($name, $email, null, 'webmaster');
	}

	/**
	 * Method to initialise the feed for parsing.  Here we detect the version and advance the stream
	 * reader so that it is ready to parse feed elements.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function initialise()
	{
		// Read the version attribute.
		$this->version = $this->stream->getAttribute('version');

		// We want to move forward to the first element after the <channel> element.
		$this->moveToNextElement('channel');
		$this->moveToNextElement();
	}

	/**
	 * Method to handle a `<item>` element for the feed.
	 *
	 * @param   FeedEntry          $entry  The FeedEntry object being built from the parsed feed entry.
	 * @param   \SimpleXMLElement  $el     The current XML element object to handle.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function processFeedEntry(FeedEntry $entry, \SimpleXMLElement $el)
	{
		$entry->uri           = (string) filter_var($el->link, FILTER_VALIDATE_URL);
		$entry->title         = $this->inputFilter->clean((string) $el->title, 'html');
		$entry->publishedDate = $this->inputFilter->clean((string) $el->pubDate, 'html');
		$entry->updatedDate   = $this->inputFilter->clean((string) $el->pubDate, 'html');
		$entry->content       = $this->inputFilter->clean((string) $el->description, 'html');
		$entry->guid          = $this->inputFilter->clean((string) $el->guid, 'html');
		$entry->isPermaLink   = $entry->guid === '' || (string) $el->guid['isPermaLink'] === 'false' ? false : true;
		$entry->comments      = $this->inputFilter->clean((string) $el->comments, 'html');

		// Add the feed entry author if available.
		$author = $this->inputFilter->clean((string) $el->author, 'html');

		if (!empty($author))
		{
			$entry->author = $this->processPerson($author);
		}

		// Add any categories to the entry.
		foreach ($el->category as $category)
		{
			$entry->addCategory((string) $category, (string) $category['domain']);
		}

		// Add any enclosures to the entry.
		foreach ($el->enclosure as $enclosure)
		{
			$link = new FeedLink(
				(string) $enclosure['url'],
				null,
				(string) $enclosure['type'],
				null,
				null,
				(int) $enclosure['length']
			);

			$entry->addLink($link);
		}
	}

	/**
	 * Method to parse a string with person data and return a FeedPerson object.
	 *
	 * @param   string  $data  The string to parse for a person.
	 *
	 * @return  FeedPerson
	 *
	 * @since   3.1.4
	 */
	protected function processPerson($data)
	{
		// Create a new person object.
		$person = new FeedPerson;

		// This is really cheap parsing, but so far good enough. :)
		$data = explode(' ', $data, 2);

		if (isset($data[1]))
		{
			$person->name = trim(
				$this->inputFilter->clean($data[1], 'html'),
				' ()'
			);
		}

		// Set the email for the person.
		$person->email = trim(
			filter_var((string) $data[0], FILTER_VALIDATE_EMAIL)
		);

		return $person;
	}
}
Feed.php000064400000021556152345403320006132 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Feed;

defined('JPATH_PLATFORM') or die();

use Joomla\CMS\Date\Date;

/**
 * Class to encapsulate a feed for the Joomla Platform.
 *
 * @property  FeedPerson     $author         Person responsible for feed content.
 * @property  array          $categories     Categories to which the feed belongs.
 * @property  array          $contributors   People who contributed to the feed content.
 * @property  string         $copyright      Information about rights, e.g. copyrights, held in and over the feed.
 * @property  string         $description    A phrase or sentence describing the feed.
 * @property  string         $generator      A string indicating the program used to generate the feed.
 * @property  FeedLink|null  $image          FeedLink object containing feed image properties.
 * @property  Date           $publishedDate  The publication date for the feed content.
 * @property  string         $title          A human readable title for the feed.
 * @property  Date           $updatedDate    The last time the content of the feed changed.
 * @property  string         $uri            Universal, permanent identifier for the feed.
 *
 * @since  3.1.4
 */
class Feed implements \ArrayAccess, \Countable
{
	/**
	 * @var    array  The entry properties.
	 * @since  3.1.4
	 */
	protected $properties = array(
		'uri' => '',
		'title' => '',
		'updatedDate' => '',
		'description' => '',
		'categories' => array(),
		'contributors' => array(),
	);

	/**
	 * @var    array  The list of feed entry objects.
	 * @since  3.1.4
	 */
	protected $entries = array();

	/**
	 * Magic method to return values for feed properties.
	 *
	 * @param   string  $name  The name of the property.
	 *
	 * @return  mixed
	 *
	 * @since   3.1.4
	 */
	public function __get($name)
	{
		return isset($this->properties[$name]) ? $this->properties[$name] : null;
	}

	/**
	 * Magic method to set values for feed properties.
	 *
	 * @param   string  $name   The name of the property.
	 * @param   mixed   $value  The value to set for the property.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	public function __set($name, $value)
	{
		// Ensure that setting a date always sets a JDate instance.
		if ((($name == 'updatedDate') || ($name == 'publishedDate')) && !($value instanceof Date))
		{
			$value = new Date($value);
		}

		// Validate that any authors that are set are instances of JFeedPerson or null.
		if (($name == 'author') && (!($value instanceof FeedPerson) || ($value === null)))
		{
			throw new \InvalidArgumentException(
				sprintf(
					'%1$s "author" must be an instance of Joomla\\CMS\\Feed\\FeedPerson. %2$s given.',
					get_class($this),
					gettype($value) === 'object' ? get_class($value) : gettype($value)
				)
			);
		}

		// Disallow setting categories or contributors directly.
		if (in_array($name, array('categories', 'contributors')))
		{
			throw new \InvalidArgumentException(
				sprintf(
					'Cannot directly set %1$s property "%2$s".',
					get_class($this),
					$name
				)
			);
		}

		$this->properties[$name] = $value;
	}

	/**
	 * Method to add a category to the feed object.
	 *
	 * @param   string  $name  The name of the category to add.
	 * @param   string  $uri   The optional URI for the category to add.
	 *
	 * @return  Feed
	 *
	 * @since   3.1.4
	 */
	public function addCategory($name, $uri = '')
	{
		$this->properties['categories'][$name] = $uri;

		return $this;
	}

	/**
	 * Method to add a contributor to the feed object.
	 *
	 * @param   string  $name   The full name of the person to add.
	 * @param   string  $email  The email address of the person to add.
	 * @param   string  $uri    The optional URI for the person to add.
	 * @param   string  $type   The optional type of person to add.
	 *
	 * @return  Feed
	 *
	 * @since   3.1.4
	 */
	public function addContributor($name, $email, $uri = null, $type = null)
	{
		$contributor = new FeedPerson($name, $email, $uri, $type);

		// If the new contributor already exists then there is nothing to do, so just return.
		foreach ($this->properties['contributors'] as $c)
		{
			if ($c == $contributor)
			{
				return $this;
			}
		}

		// Add the new contributor.
		$this->properties['contributors'][] = $contributor;

		return $this;
	}

	/**
	 * Method to add an entry to the feed object.
	 *
	 * @param   FeedEntry  $entry  The entry object to add.
	 *
	 * @return  Feed
	 *
	 * @since   3.1.4
	 */
	public function addEntry(FeedEntry $entry)
	{
		// If the new entry already exists then there is nothing to do, so just return.
		foreach ($this->entries as $e)
		{
			if ($e == $entry)
			{
				return $this;
			}
		}

		// Add the new entry.
		$this->entries[] = $entry;

		return $this;
	}

	/**
	 * Returns a count of the number of entries in the feed.
	 *
	 * This method is here to implement the Countable interface.
	 * You can call it by doing count($feed) rather than $feed->count();
	 *
	 * @return  integer number of entries in the feed.
	 */
	public function count()
	{
		return count($this->entries);
	}

	/**
	 * Whether or not an offset exists.  This method is executed when using isset() or empty() on
	 * objects implementing ArrayAccess.
	 *
	 * @param   mixed  $offset  An offset to check for.
	 *
	 * @return  boolean
	 *
	 * @see     ArrayAccess::offsetExists()
	 * @since   3.1.4
	 */
	public function offsetExists($offset)
	{
		return isset($this->entries[$offset]);
	}

	/**
	 * Returns the value at specified offset.
	 *
	 * @param   mixed  $offset  The offset to retrieve.
	 *
	 * @return  mixed  The value at the offset.
	 *
	 * @see     ArrayAccess::offsetGet()
	 * @since   3.1.4
	 */
	public function offsetGet($offset)
	{
		return $this->entries[$offset];
	}

	/**
	 * Assigns a value to the specified offset.
	 *
	 * @param   mixed      $offset  The offset to assign the value to.
	 * @param   FeedEntry  $value   The JFeedEntry to set.
	 *
	 * @return  boolean
	 *
	 * @see     ArrayAccess::offsetSet()
	 * @since   3.1.4
	 * @throws  \InvalidArgumentException
	 */
	public function offsetSet($offset, $value)
	{
		if (!($value instanceof FeedEntry))
		{
			throw new \InvalidArgumentException(
				sprintf(
					'%1$s entries must be an instance of Joomla\\CMS\\Feed\\FeedPerson. %2$s given.',
					get_class($this),
					gettype($value) === 'object' ? get_class($value) : gettype($value)
				)
			);
		}

		$this->entries[$offset] = $value;

		return true;
	}

	/**
	 * Unsets an offset.
	 *
	 * @param   mixed  $offset  The offset to unset.
	 *
	 * @return  void
	 *
	 * @see     ArrayAccess::offsetUnset()
	 * @since   3.1.4
	 */
	public function offsetUnset($offset)
	{
		unset($this->entries[$offset]);
	}

	/**
	 * Method to remove a category from the feed object.
	 *
	 * @param   string  $name  The name of the category to remove.
	 *
	 * @return  Feed
	 *
	 * @since   3.1.4
	 */
	public function removeCategory($name)
	{
		unset($this->properties['categories'][$name]);

		return $this;
	}

	/**
	 * Method to remove a contributor from the feed object.
	 *
	 * @param   FeedPerson  $contributor  The person object to remove.
	 *
	 * @return  Feed
	 *
	 * @since   3.1.4
	 */
	public function removeContributor(FeedPerson $contributor)
	{
		// If the contributor exists remove it.
		foreach ($this->properties['contributors'] as $k => $c)
		{
			if ($c == $contributor)
			{
				unset($this->properties['contributors'][$k]);
				$this->properties['contributors'] = array_values($this->properties['contributors']);

				return $this;
			}
		}

		return $this;
	}

	/**
	 * Method to remove an entry from the feed object.
	 *
	 * @param   FeedEntry  $entry  The entry object to remove.
	 *
	 * @return  Feed
	 *
	 * @since   3.1.4
	 */
	public function removeEntry(FeedEntry $entry)
	{
		// If the entry exists remove it.
		foreach ($this->entries as $k => $e)
		{
			if ($e == $entry)
			{
				unset($this->entries[$k]);
				$this->entries = array_values($this->entries);

				return $this;
			}
		}

		return $this;
	}

	/**
	 * Shortcut method to set the author for the feed object.
	 *
	 * @param   string  $name   The full name of the person to set.
	 * @param   string  $email  The email address of the person to set.
	 * @param   string  $uri    The optional URI for the person to set.
	 * @param   string  $type   The optional type of person to set.
	 *
	 * @return  Feed
	 *
	 * @since   3.1.4
	 */
	public function setAuthor($name, $email, $uri = null, $type = null)
	{
		$author = new FeedPerson($name, $email, $uri, $type);

		$this->properties['author'] = $author;

		return $this;
	}

	/**
	 * Method to reverse the items if display is set to 'oldest first'
	 *
	 * @return  Feed
	 *
	 * @since   3.1.4
	 */
	public function reverseItems()
	{
		if (is_array($this->entries) && !empty($this->entries))
		{
			$this->entries = array_reverse($this->entries);
		}

		return $this;
	}
}
FeedEntry.php000064400000016074152345403320007153 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Feed;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Date\Date;

/**
 * Class to encapsulate a feed entry for the Joomla Platform.
 *
 * @property  FeedPerson  $author         Person responsible for feed entry content.
 * @property  array       $categories     Categories to which the feed entry belongs.
 * @property  string      $content        The content of the feed entry.
 * @property  array       $contributors   People who contributed to the feed entry content.
 * @property  string      $copyright      Information about rights, e.g. copyrights, held in and over the feed entry.
 * @property  array       $links          Links associated with the feed entry.
 * @property  Date        $publishedDate  The publication date for the feed entry.
 * @property  Feed        $source         The feed from which the entry is sourced.
 * @property  string      $title          A human readable title for the feed entry.
 * @property  Date        $updatedDate    The last time the content of the feed entry changed.
 * @property  string      $uri            Universal, permanent identifier for the feed entry.
 *
 * @since  3.1.4
 */
class FeedEntry
{
	/**
	 * @var    array  The entry properties.
	 * @since  3.1.4
	 */
	protected $properties = array(
		'uri'  => '',
		'title' => '',
		'updatedDate' => '',
		'content' => '',
		'categories' => array(),
		'contributors' => array(),
		'links' => array(),
	);

	/**
	 * Magic method to return values for feed entry properties.
	 *
	 * @param   string  $name  The name of the property.
	 *
	 * @return  mixed
	 *
	 * @since   3.1.4
	 */
	public function __get($name)
	{
		return (isset($this->properties[$name])) ? $this->properties[$name] : null;
	}

	/**
	 * Magic method to set values for feed properties.
	 *
	 * @param   string  $name   The name of the property.
	 * @param   mixed   $value  The value to set for the property.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	public function __set($name, $value)
	{
		// Ensure that setting a date always sets a JDate instance.
		if ((($name == 'updatedDate') || ($name == 'publishedDate')) && !($value instanceof Date))
		{
			$value = new Date($value);
		}

		// Validate that any authors that are set are instances of JFeedPerson or null.
		if (($name == 'author') && (!($value instanceof FeedPerson) || ($value === null)))
		{
			throw new \InvalidArgumentException(
				sprintf(
					'%1$s "author" must be an instance of Joomla\\CMS\\Feed\\FeedPerson. %2$s given.',
					get_class($this),
					gettype($value) === 'object' ? get_class($value) : gettype($value)
				)
			);
		}

		// Validate that any sources that are set are instances of JFeed or null.
		if (($name == 'source') && (!($value instanceof Feed) || ($value === null)))
		{
			throw new \InvalidArgumentException(
				sprintf(
					'%1$s "source" must be an instance of Joomla\\CMS\\Feed\\Feed. %2$s given.',
					get_class($this),
					gettype($value) === 'object' ? get_class($value) : gettype($value)
				)
			);
		}

		// Disallow setting categories, contributors, or links directly.
		if (in_array($name, array('categories', 'contributors', 'links')))
		{
			throw new \InvalidArgumentException(
				sprintf(
					'Cannot directly set %1$s property "%2$s".',
					get_class($this),
					$name
				)
			);
		}

		$this->properties[$name] = $value;
	}

	/**
	 * Method to add a category to the feed entry object.
	 *
	 * @param   string  $name  The name of the category to add.
	 * @param   string  $uri   The optional URI for the category to add.
	 *
	 * @return  FeedEntry
	 *
	 * @since   3.1.4
	 */
	public function addCategory($name, $uri = '')
	{
		$this->properties['categories'][$name] = $uri;

		return $this;
	}

	/**
	 * Method to add a contributor to the feed entry object.
	 *
	 * @param   string  $name   The full name of the person to add.
	 * @param   string  $email  The email address of the person to add.
	 * @param   string  $uri    The optional URI for the person to add.
	 * @param   string  $type   The optional type of person to add.
	 *
	 * @return  FeedEntry
	 *
	 * @since   3.1.4
	 */
	public function addContributor($name, $email, $uri = null, $type = null)
	{
		$contributor = new FeedPerson($name, $email, $uri, $type);

		// If the new contributor already exists then there is nothing to do, so just return.
		foreach ($this->properties['contributors'] as $c)
		{
			if ($c == $contributor)
			{
				return $this;
			}
		}

		// Add the new contributor.
		$this->properties['contributors'][] = $contributor;

		return $this;
	}

	/**
	 * Method to add a link to the feed entry object.
	 *
	 * @param   FeedLink  $link  The link object to add.
	 *
	 * @return  FeedEntry
	 *
	 * @since   3.1.4
	 */
	public function addLink(FeedLink $link)
	{
		// If the new link already exists then there is nothing to do, so just return.
		foreach ($this->properties['links'] as $l)
		{
			if ($l == $link)
			{
				return $this;
			}
		}

		// Add the new link.
		$this->properties['links'][] = $link;

		return $this;
	}

	/**
	 * Method to remove a category from the feed entry object.
	 *
	 * @param   string  $name  The name of the category to remove.
	 *
	 * @return  FeedEntry
	 *
	 * @since   3.1.4
	 */
	public function removeCategory($name)
	{
		unset($this->properties['categories'][$name]);

		return $this;
	}

	/**
	 * Method to remove a contributor from the feed entry object.
	 *
	 * @param   FeedPerson  $contributor  The person object to remove.
	 *
	 * @return  FeedEntry
	 *
	 * @since   3.1.4
	 */
	public function removeContributor(FeedPerson $contributor)
	{
		// If the contributor exists remove it.
		foreach ($this->properties['contributors'] as $k => $c)
		{
			if ($c == $contributor)
			{
				unset($this->properties['contributors'][$k]);
				$this->properties['contributors'] = array_values($this->properties['contributors']);

				return $this;
			}
		}

		return $this;
	}

	/**
	 * Method to remove a link from the feed entry object.
	 *
	 * @param   FeedLink  $link  The link object to remove.
	 *
	 * @return  FeedEntry
	 *
	 * @since   3.1.4
	 */
	public function removeLink(FeedLink $link)
	{
		// If the link exists remove it.
		foreach ($this->properties['links'] as $k => $l)
		{
			if ($l == $link)
			{
				unset($this->properties['links'][$k]);
				$this->properties['links'] = array_values($this->properties['links']);

				return $this;
			}
		}

		return $this;
	}

	/**
	 * Shortcut method to set the author for the feed entry object.
	 *
	 * @param   string  $name   The full name of the person to set.
	 * @param   string  $email  The email address of the person to set.
	 * @param   string  $uri    The optional URI for the person to set.
	 * @param   string  $type   The optional type of person to set.
	 *
	 * @return  FeedEntry
	 *
	 * @since   3.1.4
	 */
	public function setAuthor($name, $email, $uri = null, $type = null)
	{
		$author = new FeedPerson($name, $email, $uri, $type);

		$this->properties['author'] = $author;

		return $this;
	}
}
FeedFactory.php000064400000010154152345403320007452 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Feed;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Http\HttpFactory;
use Joomla\Registry\Registry;

/**
 * Feed factory class.
 *
 * @since  3.1.4
 */
class FeedFactory
{
	/**
	 * @var    array  The list of registered parser classes for feeds.
	 * @since  3.1.4
	 */
	protected $parsers = array('rss' => 'Joomla\\CMS\\Feed\\Parser\\RssParser', 'feed' => 'Joomla\\CMS\\Feed\\Parser\\AtomParser');

	/**
	 * Method to load a URI into the feed reader for parsing.
	 *
	 * @param   string  $uri  The URI of the feed to load. Idn uris must be passed already converted to punycode.
	 *
	 * @return  Feed
	 *
	 * @since   3.1.4
	 * @throws  \InvalidArgumentException
	 * @throws  \RuntimeException
	 */
	public function getFeed($uri)
	{
		// Create the XMLReader object.
		$reader = new \XMLReader;

		// Open the URI within the stream reader.
		if (!@$reader->open($uri, null, LIBXML_NOERROR | LIBXML_ERR_NONE | LIBXML_NOWARNING))
		{
			// Retry with JHttpFactory that allow using CURL and Sockets as alternative method when available

			// Adding a valid user agent string, otherwise some feed-servers returning an error
			$options = new Registry;
			$options->set('userAgent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0');

			try
			{
				$response = HttpFactory::getHttp($options)->get($uri);
			}
			catch (RuntimeException $e)
			{
				throw new \RuntimeException('Unable to open the feed.', $e->getCode(), $e);
			}

			if ($response->code != 200)
			{
				throw new \RuntimeException('Unable to open the feed.');
			}

			// Set the value to the XMLReader parser
			if (!$reader->xml($response->body, null, LIBXML_NOERROR | LIBXML_ERR_NONE | LIBXML_NOWARNING))
			{
				throw new \RuntimeException('Unable to parse the feed.');
			}
		}

		try
		{
			// Skip ahead to the root node.
			while ($reader->read())
			{
				if ($reader->nodeType == \XMLReader::ELEMENT)
				{
					break;
				}
			}
		}
		catch (\Exception $e)
		{
			throw new \RuntimeException('Error reading feed.', $e->getCode(), $e);
		}

		// Setup the appropriate feed parser for the feed.
		$parser = $this->_fetchFeedParser($reader->name, $reader);

		return $parser->parse();
	}

	/**
	 * Method to register a FeedParser class for a given root tag name.
	 *
	 * @param   string   $tagName    The root tag name for which to register the parser class.
	 * @param   string   $className  The FeedParser class name to register for a root tag name.
	 * @param   boolean  $overwrite  True to overwrite the parser class if one is already registered.
	 *
	 * @return  FeedFactory
	 *
	 * @since   3.1.4
	 * @throws  \InvalidArgumentException
	 */
	public function registerParser($tagName, $className, $overwrite = false)
	{
		// Verify that the class exists.
		if (!class_exists($className))
		{
			throw new \InvalidArgumentException('The feed parser class ' . $className . ' does not exist.');
		}

		// Validate that the tag name is valid.
		if (!preg_match('/\A(?!XML)[a-z][\w0-9-]*/i', $tagName))
		{
			throw new \InvalidArgumentException('The tag name ' . $tagName . ' is not valid.');
		}

		// Register the given parser class for the tag name if nothing registered or the overwrite flag set.
		if (empty($this->parsers[$tagName]) || (bool) $overwrite)
		{
			$this->parsers[(string) $tagName] = (string) $className;
		}

		return $this;
	}

	/**
	 * Method to return a new JFeedParser object based on the registered parsers and a given type.
	 *
	 * @param   string      $type    The name of parser to return.
	 * @param   \XMLReader  $reader  The XMLReader instance for the feed.
	 *
	 * @return  FeedParser
	 *
	 * @since   3.1.4
	 * @throws  \LogicException
	 */
	private function _fetchFeedParser($type, \XMLReader $reader)
	{
		// Look for a registered parser for the feed type.
		if (empty($this->parsers[$type]))
		{
			throw new \LogicException('No registered feed parser for type ' . $type . '.');
		}

		return new $this->parsers[$type]($reader);
	}
}
FeedLink.php000064400000003660152345403320006744 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Feed;

defined('JPATH_PLATFORM') or die;

/**
 * Feed Link class.
 *
 * @since  3.1.4
 */
class FeedLink
{
	/**
	 * The URI to the linked resource.
	 *
	 * @var    string
	 * @since  3.1.4
	 */
	public $uri;

	/**
	 * The relationship between the feed and the linked resource.
	 *
	 * @var    string
	 * @since  3.1.4
	 */
	public $relation;

	/**
	 * The resource type.
	 *
	 * @var    string
	 * @since  3.1.4
	 */
	public $type;

	/**
	 * The language of the resource found at the given URI.
	 *
	 * @var    string
	 * @since  3.1.4
	 */
	public $language;

	/**
	 * The title of the resource.
	 *
	 * @var    string
	 * @since  3.1.4
	 */
	public $title;

	/**
	 * The length of the resource in bytes.
	 *
	 * @var    integer
	 * @since  3.1.4
	 */
	public $length;

	/**
	 * Constructor.
	 *
	 * @param   string   $uri       The URI to the linked resource.
	 * @param   string   $relation  The relationship between the feed and the linked resource.
	 * @param   string   $type      The resource type.
	 * @param   string   $language  The language of the resource found at the given URI.
	 * @param   string   $title     The title of the resource.
	 * @param   integer  $length    The length of the resource in bytes.
	 *
	 * @since   3.1.4
	 * @throws  \InvalidArgumentException
	 */
	public function __construct($uri = null, $relation = null, $type = null, $language = null, $title = null, $length = null)
	{
		$this->uri = $uri;
		$this->relation = $relation;
		$this->type = $type;
		$this->language = $language;
		$this->title = $title;

		// Validate the length input.
		if (isset($length) && !is_numeric($length))
		{
			throw new \InvalidArgumentException('Length must be numeric.');
		}

		$this->length = (int) $length;
	}
}
FeedParser.php000064400000015470152345403320007305 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Feed;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Feed\Parser\NamespaceParserInterface;
use Joomla\CMS\Filter\InputFilter;

/**
 * Feed Parser class.
 *
 * @since  3.1.4
 */
abstract class FeedParser
{
	/**
	 * The feed element name for the entry elements.
	 *
	 * @var    string
	 * @since  3.1.4
	 */
	protected $entryElementName = 'entry';

	/**
	 * Array of NamespaceParserInterface objects
	 *
	 * @var    array
	 * @since  3.1.4
	 */
	protected $namespaces = array();

	/**
	 * The XMLReader stream object for the feed.
	 *
	 * @var    \XMLReader
	 * @since  3.1.4
	 */
	protected $stream;

	/**
	 * The InputFilter
	 *
	 * @var    InputFilter
	 * @since  3.9.25
	 */
	protected $inputFilter;

	/**
	 * Constructor.
	 *
	 * @param   \XMLReader   $stream       The XMLReader stream object for the feed.
	 * @param   InputFilter  $inputFilter  The InputFilter object to be used
	 *
	 * @since   3.1.4
	 */
	public function __construct(\XMLReader $stream, InputFilter $inputFilter = null)
	{
		$this->stream      = $stream;
		$this->inputFilter = $inputFilter ? $inputFilter : InputFilter::getInstance(array(), array(), 1, 1);
	}

	/**
	 * Method to parse the feed into a JFeed object.
	 *
	 * @return  Feed
	 *
	 * @since   3.1.4
	 */
	public function parse()
	{
		$feed = new Feed;

		// Detect the feed version.
		$this->initialise();

		// Let's get this party started...
		do
		{
			// Expand the element for processing.
			$el = new \SimpleXMLElement($this->stream->readOuterXml());

			// Get the list of namespaces used within this element.
			$ns = $el->getNamespaces(true);

			// Get an array of available namespace objects for the element.
			$namespaces = array();

			foreach ($ns as $prefix => $uri)
			{
				// Ignore the empty namespace prefix.
				if (empty($prefix))
				{
					continue;
				}

				// Get the necessary namespace objects for the element.
				$namespace = $this->fetchNamespace($prefix);

				if ($namespace)
				{
					$namespaces[] = $namespace;
				}
			}

			// Process the element.
			$this->processElement($feed, $el, $namespaces);

			// Skip over this element's children since it has been processed.
			$this->moveToClosingElement();
		}

		while ($this->moveToNextElement());

		return $feed;
	}

	/**
	 * Method to register a namespace handler object.
	 *
	 * @param   string                    $prefix     The XML namespace prefix for which to register the namespace object.
	 * @param   NamespaceParserInterface  $namespace  The namespace object to register.
	 *
	 * @return  JFeed
	 *
	 * @since   3.1.4
	 */
	public function registerNamespace($prefix, NamespaceParserInterface $namespace)
	{
		$this->namespaces[$prefix] = $namespace;

		return $this;
	}

	/**
	 * Method to initialise the feed for parsing.  If child parsers need to detect versions or other
	 * such things this is where you'll want to implement that logic.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	abstract protected function initialise();

	/**
	 * Method to parse a specific feed element.
	 *
	 * @param   Feed               $feed        The Feed object being built from the parsed feed.
	 * @param   \SimpleXMLElement  $el          The current XML element object to handle.
	 * @param   array              $namespaces  The array of relevant namespace objects to process for the element.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 */
	protected function processElement(Feed $feed, \SimpleXMLElement $el, array $namespaces)
	{
		// Build the internal method name.
		$method = 'handle' . ucfirst($el->getName());

		// If we are dealing with an item then it is feed entry time.
		if ($el->getName() == $this->entryElementName)
		{
			// Create a new feed entry for the item.
			$entry = new FeedEntry;

			// First call the internal method.
			$this->processFeedEntry($entry, $el);

			foreach ($namespaces as $namespace)
			{
				if ($namespace instanceof NamespaceParserInterface)
				{
					$namespace->processElementForFeedEntry($entry, $el);
				}
			}

			// Add the new entry to the feed.
			$feed->addEntry($entry);

			return;
		}

		// Otherwise we treat it like any other element.

		// First call the internal method.
		if (is_callable(array($this, $method)))
		{
			$this->$method($feed, $el);
		}

		foreach ($namespaces as $namespace)
		{
			if ($namespace instanceof NamespaceParserInterface)
			{
				$namespace->processElementForFeed($feed, $el);
			}
		}
	}

	/**
	 * Method to get a namespace object for a given namespace prefix.
	 *
	 * @param   string  $prefix  The XML prefix for which to fetch the namespace object.
	 *
	 * @return  mixed  NamespaceParserInterface or false if none exists.
	 *
	 * @since   3.1.4
	 */
	protected function fetchNamespace($prefix)
	{
		if (isset($this->namespaces[$prefix]))
		{
			return $this->namespaces[$prefix];
		}

		$className = get_class($this) . ucfirst($prefix);

		if (class_exists($className))
		{
			$this->namespaces[$prefix] = new $className;

			return $this->namespaces[$prefix];
		}

		return false;
	}

	/**
	 * Method to move the stream parser to the next XML element node.
	 *
	 * @param   string  $name  The name of the element for which to move the stream forward until is found.
	 *
	 * @return  boolean  True if the stream parser is on an XML element node.
	 *
	 * @since   3.1.4
	 */
	protected function moveToNextElement($name = null)
	{
		// Only keep looking until the end of the stream.
		while ($this->stream->read())
		{
			// As soon as we get to the next ELEMENT node we are done.
			if ($this->stream->nodeType == \XMLReader::ELEMENT)
			{
				// If we are looking for a specific name make sure we have it.
				if (isset($name) && ($this->stream->name != $name))
				{
					continue;
				}

				return true;
			}
		}

		return false;
	}

	/**
	 * Method to move the stream parser to the closing XML node of the current element.
	 *
	 * @return  void
	 *
	 * @since   3.1.4
	 * @throws  \RuntimeException  If the closing tag cannot be found.
	 */
	protected function moveToClosingElement()
	{
		// If we are on a self-closing tag then there is nothing to do.
		if ($this->stream->isEmptyElement)
		{
			return;
		}

		// Get the name and depth for the current node so that we can match the closing node.
		$name  = $this->stream->name;
		$depth = $this->stream->depth;

		// Only keep looking until the end of the stream.
		while ($this->stream->read())
		{
			// If we have an END_ELEMENT node with the same name and depth as the node we started with we have a bingo. :-)
			if (($this->stream->name == $name) && ($this->stream->depth == $depth) && ($this->stream->nodeType == \XMLReader::END_ELEMENT))
			{
				return;
			}
		}

		throw new \RuntimeException('Unable to find the closing XML node.');
	}
}
FeedPerson.php000064400000002247152345403320007315 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Feed;

defined('JPATH_PLATFORM') or die;

/**
 * Feed Person class.
 *
 * @since  3.1.4
 */
class FeedPerson
{
	/**
	 * The email address of the person.
	 *
	 * @var    string
	 * @since  3.1.4
	 */
	public $email;

	/**
	 * The full name of the person.
	 *
	 * @var    string
	 * @since  3.1.4
	 */
	public $name;

	/**
	 * The type of person.
	 *
	 * @var    string
	 * @since  3.1.4
	 */
	public $type;

	/**
	 * The URI for the person.
	 *
	 * @var    string
	 * @since  3.1.4
	 */
	public $uri;

	/**
	 * Constructor.
	 *
	 * @param   string  $name   The full name of the person.
	 * @param   string  $email  The email address of the person.
	 * @param   string  $uri    The URI for the person.
	 * @param   string  $type   The type of person.
	 *
	 * @since   3.1.4
	 */
	public function __construct($name = null, $email = null, $uri = null, $type = null)
	{
		$this->name = $name;
		$this->email = $email;
		$this->uri = $uri;
		$this->type = $type;
	}
}
FeedEnclosure.php000064400000001326152346314720010011 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Document\Feed;

defined('JPATH_PLATFORM') or die;

/**
 * Data object representing a feed enclosure
 *
 * @since  1.7.0
 */
class FeedEnclosure
{
	/**
	 * URL enclosure element
	 *
	 * required
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $url = '';

	/**
	 * Length enclosure element
	 *
	 * required
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $length = '';

	/**
	 * Type enclosure element
	 *
	 * required
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $type = '';
}
FeedImage.php000064400000002030152346314720007065 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Document\Feed;

defined('JPATH_PLATFORM') or die;

/**
 * Data object representing a feed image
 *
 * @since  1.7.0
 */
class FeedImage
{
	/**
	 * Title image attribute
	 *
	 * required
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $title = '';

	/**
	 * URL image attribute
	 *
	 * required
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $url = '';

	/**
	 * Link image attribute
	 *
	 * required
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $link = '';

	/**
	 * Width image attribute
	 *
	 * optional
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $width;

	/**
	 * Title feed attribute
	 *
	 * optional
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $height;

	/**
	 * Title feed attribute
	 *
	 * optional
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $description;
}
FeedItem.php000064400000004077152346314720006756 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Document\Feed;

defined('JPATH_PLATFORM') or die;

/**
 * Data object representing a feed item
 *
 * @since  1.7.0
 */
class FeedItem
{
	/**
	 * Title item element
	 *
	 * required
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $title;

	/**
	 * Link item element
	 *
	 * required
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $link;

	/**
	 * Description item element
	 *
	 * required
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $description;

	/**
	 * Author item element
	 *
	 * optional
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $author;

	/**
	 * Author email element
	 *
	 * optional
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $authorEmail;

	/**
	 * Category element
	 *
	 * optional
	 *
	 * @var    array or string
	 * @since  1.7.0
	 */
	public $category;

	/**
	 * Comments element
	 *
	 * optional
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $comments;

	/**
	 * Enclosure element
	 *
	 * @var    FeedEnclosure
	 * @since  1.7.0
	 */
	public $enclosure = null;

	/**
	 * Guid element
	 *
	 * optional
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $guid;

	/**
	 * Published date
	 *
	 * optional
	 *
	 * May be in one of the following formats:
	 *
	 * RFC 822:
	 * "Mon, 20 Jan 03 18:05:41 +0400"
	 * "20 Jan 03 18:05:41 +0000"
	 *
	 * ISO 8601:
	 * "2003-01-20T18:05:41+04:00"
	 *
	 * Unix:
	 * 1043082341
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $date;

	/**
	 * Source element
	 *
	 * optional
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	public $source;

	/**
	 * Set the FeedEnclosure for this item
	 *
	 * @param   FeedEnclosure  $enclosure  The FeedEnclosure to add to the feed.
	 *
	 * @return  FeedItem instance of $this to allow chaining
	 *
	 * @since   1.7.0
	 */
	public function setEnclosure(FeedEnclosure $enclosure)
	{
		$this->enclosure = $enclosure;

		return $this;
	}
}
RssRenderer.php000064400000017600152357725770007543 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2015 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Document\Renderer\Feed;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Document\DocumentRenderer;
use Joomla\CMS\Uri\Uri;

/**
 * RssRenderer is a feed that implements RSS 2.0 Specification
 *
 * @link   http://www.rssboard.org/rss-specification
 * @since  3.5
 *
 * @property-read  \Joomla\CMS\Document\FeedDocument  $_doc  Reference to the Document object that instantiated the renderer
 */
class RssRenderer extends DocumentRenderer
{
	/**
	 * Renderer mime type
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $_mime = 'application/rss+xml';

	/**
	 * Render the feed.
	 *
	 * @param   string  $name     The name of the element to render
	 * @param   array   $params   Array of values
	 * @param   string  $content  Override the output of the renderer
	 *
	 * @return  string  The output of the script
	 *
	 * @see     DocumentRenderer::render()
	 * @since   3.5
	 */
	public function render($name = '', $params = null, $content = null)
	{
		$app = \JFactory::getApplication();

		// Gets and sets timezone offset from site configuration
		$tz  = new \DateTimeZone($app->get('offset'));
		$now = \JFactory::getDate();
		$now->setTimeZone($tz);

		$data = $this->_doc;

		$url = Uri::getInstance()->toString(array('scheme', 'user', 'pass', 'host', 'port'));
		$syndicationURL = \JRoute::_('&format=feed&type=rss');

		$title = $data->getTitle();

		if ($app->get('sitename_pagetitles', 0) == 1)
		{
			$title = \JText::sprintf('JPAGETITLE', $app->get('sitename'), $data->getTitle());
		}
		elseif ($app->get('sitename_pagetitles', 0) == 2)
		{
			$title = \JText::sprintf('JPAGETITLE', $data->getTitle(), $app->get('sitename'));
		}

		$feed_title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8');

		$datalink = $data->getLink();

		if (preg_match('/[\x80-\xFF]/', $datalink))
		{
			$datalink = implode('/', array_map('rawurlencode', explode('/', $datalink)));
		}

		$feed = "<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n";
		$feed .= "	<channel>\n";
		$feed .= "		<title>" . $feed_title . "</title>\n";
		$feed .= "		<description><![CDATA[" . $data->getDescription() . "]]></description>\n";
		$feed .= "		<link>" . str_replace(' ', '%20', $url . $datalink) . "</link>\n";
		$feed .= "		<lastBuildDate>" . htmlspecialchars($now->toRFC822(true), ENT_COMPAT, 'UTF-8') . "</lastBuildDate>\n";
		$feed .= "		<generator>" . $data->getGenerator() . "</generator>\n";
		$feed .= "		<atom:link rel=\"self\" type=\"application/rss+xml\" href=\"" . str_replace(' ', '%20', $url . $syndicationURL) . "\"/>\n";

		if ($data->image != null)
		{
			$feed .= "		<image>\n";
			$feed .= "			<url>" . $data->image->url . "</url>\n";
			$feed .= "			<title>" . htmlspecialchars($data->image->title, ENT_COMPAT, 'UTF-8') . "</title>\n";
			$feed .= "			<link>" . str_replace(' ', '%20', $data->image->link) . "</link>\n";

			if ($data->image->width != '')
			{
				$feed .= "			<width>" . $data->image->width . "</width>\n";
			}

			if ($data->image->height != '')
			{
				$feed .= "			<height>" . $data->image->height . "</height>\n";
			}

			if ($data->image->description != '')
			{
				$feed .= "			<description><![CDATA[" . $data->image->description . "]]></description>\n";
			}

			$feed .= "		</image>\n";
		}

		if ($data->getLanguage() !== '')
		{
			$feed .= "		<language>" . $data->getLanguage() . "</language>\n";
		}

		if ($data->copyright != '')
		{
			$feed .= "		<copyright>" . htmlspecialchars($data->copyright, ENT_COMPAT, 'UTF-8') . "</copyright>\n";
		}

		if ($data->editorEmail != '')
		{
			$feed .= "		<managingEditor>" . htmlspecialchars($data->editorEmail, ENT_COMPAT, 'UTF-8') . ' ('
				. htmlspecialchars($data->editor, ENT_COMPAT, 'UTF-8') . ")</managingEditor>\n";
		}

		if ($data->webmaster != '')
		{
			$feed .= "		<webMaster>" . htmlspecialchars($data->webmaster, ENT_COMPAT, 'UTF-8') . "</webMaster>\n";
		}

		if ($data->pubDate != '')
		{
			$pubDate = \JFactory::getDate($data->pubDate);
			$pubDate->setTimeZone($tz);
			$feed .= "		<pubDate>" . htmlspecialchars($pubDate->toRFC822(true), ENT_COMPAT, 'UTF-8') . "</pubDate>\n";
		}

		if (!empty($data->category))
		{
			if (is_array($data->category))
			{
				foreach ($data->category as $cat)
				{
					$feed .= "		<category>" . htmlspecialchars($cat, ENT_COMPAT, 'UTF-8') . "</category>\n";
				}
			}
			else
			{
				$feed .= "		<category>" . htmlspecialchars($data->category, ENT_COMPAT, 'UTF-8') . "</category>\n";
			}
		}

		if ($data->docs != '')
		{
			$feed .= "		<docs>" . htmlspecialchars($data->docs, ENT_COMPAT, 'UTF-8') . "</docs>\n";
		}

		if ($data->ttl != '')
		{
			$feed .= "		<ttl>" . htmlspecialchars($data->ttl, ENT_COMPAT, 'UTF-8') . "</ttl>\n";
		}

		if ($data->rating != '')
		{
			$feed .= "		<rating>" . htmlspecialchars($data->rating, ENT_COMPAT, 'UTF-8') . "</rating>\n";
		}

		if ($data->skipHours != '')
		{
			$feed .= "		<skipHours>" . htmlspecialchars($data->skipHours, ENT_COMPAT, 'UTF-8') . "</skipHours>\n";
		}

		if ($data->skipDays != '')
		{
			$feed .= "		<skipDays>" . htmlspecialchars($data->skipDays, ENT_COMPAT, 'UTF-8') . "</skipDays>\n";
		}

		for ($i = 0, $count = count($data->items); $i < $count; $i++)
		{
			$itemlink = $data->items[$i]->link;

			if (preg_match('/[\x80-\xFF]/', $itemlink))
			{
				$itemlink = implode('/', array_map('rawurlencode', explode('/', $itemlink)));
			}

			if ((strpos($itemlink, 'http://') === false) && (strpos($itemlink, 'https://') === false))
			{
				$itemlink = str_replace(' ', '%20', $url . $itemlink);
			}

			$feed .= "		<item>\n";
			$feed .= "			<title>" . htmlspecialchars(strip_tags($data->items[$i]->title), ENT_COMPAT, 'UTF-8') . "</title>\n";
			$feed .= "			<link>" . str_replace(' ', '%20', $itemlink) . "</link>\n";

			if (empty($data->items[$i]->guid))
			{
				$feed .= "			<guid isPermaLink=\"true\">" . str_replace(' ', '%20', $itemlink) . "</guid>\n";
			}
			else
			{
				$feed .= "			<guid isPermaLink=\"false\">" . htmlspecialchars($data->items[$i]->guid, ENT_COMPAT, 'UTF-8') . "</guid>\n";
			}

			$feed .= "			<description><![CDATA[" . $this->_relToAbs($data->items[$i]->description) . "]]></description>\n";

			if ($data->items[$i]->authorEmail != '')
			{
				$feed .= '			<author>'
					. htmlspecialchars($data->items[$i]->authorEmail . ' (' . $data->items[$i]->author . ')', ENT_COMPAT, 'UTF-8') . "</author>\n";
			}

			/*
			 * @todo: On hold
			 * if ($data->items[$i]->source!='')
			 * {
			 *   $data.= "			<source>" . htmlspecialchars($data->items[$i]->source, ENT_COMPAT, 'UTF-8') . "</source>\n";
			 * }
			 */

			if (empty($data->items[$i]->category) === false)
			{
				if (is_array($data->items[$i]->category))
				{
					foreach ($data->items[$i]->category as $cat)
					{
						$feed .= "			<category>" . htmlspecialchars($cat, ENT_COMPAT, 'UTF-8') . "</category>\n";
					}
				}
				else
				{
					$feed .= "			<category>" . htmlspecialchars($data->items[$i]->category, ENT_COMPAT, 'UTF-8') . "</category>\n";
				}
			}

			if ($data->items[$i]->comments != '')
			{
				$feed .= "			<comments>" . htmlspecialchars($data->items[$i]->comments, ENT_COMPAT, 'UTF-8') . "</comments>\n";
			}

			if ($data->items[$i]->date != '')
			{
				$itemDate = \JFactory::getDate($data->items[$i]->date);
				$itemDate->setTimeZone($tz);
				$feed .= "			<pubDate>" . htmlspecialchars($itemDate->toRFC822(true), ENT_COMPAT, 'UTF-8') . "</pubDate>\n";
			}

			if ($data->items[$i]->enclosure != null)
			{
				$feed .= "			<enclosure url=\"";
				$feed .= $data->items[$i]->enclosure->url;
				$feed .= "\" length=\"";
				$feed .= $data->items[$i]->enclosure->length;
				$feed .= "\" type=\"";
				$feed .= $data->items[$i]->enclosure->type;
				$feed .= "\"/>\n";
			}

			$feed .= "		</item>\n";
		}

		$feed .= "	</channel>\n";
		$feed .= "</rss>\n";

		return $feed;
	}
}
AtomRenderer.php000064400000014743152357725770007701 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  (C) 2015 Open Source Matters, Inc. <https://www.joomla.org>
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Document\Renderer\Feed;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Document\DocumentRenderer;
use Joomla\CMS\Uri\Uri;

/**
 * AtomRenderer is a feed that implements the atom specification
 *
 * Please note that just by using this class you won't automatically
 * produce valid atom files. For example, you have to specify either an editor
 * for the feed or an author for every single feed item.
 *
 * @link   http://www.atomenabled.org/developers/syndication/atom-format-spec.php
 * @since  3.5
 *
 * @property-read  \Joomla\CMS\Document\FeedDocument  $_doc  Reference to the Document object that instantiated the renderer
 */
class AtomRenderer extends DocumentRenderer
{
	/**
	 * Document mime type
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $_mime = 'application/atom+xml';

	/**
	 * Render the feed.
	 *
	 * @param   string  $name     The name of the element to render
	 * @param   array   $params   Array of values
	 * @param   string  $content  Override the output of the renderer
	 *
	 * @return  string  The output of the script
	 *
	 * @see     DocumentRenderer::render()
	 * @since   3.5
	 */
	public function render($name = '', $params = null, $content = null)
	{
		$app = \JFactory::getApplication();

		// Gets and sets timezone offset from site configuration
		$tz  = new \DateTimeZone($app->get('offset'));
		$now = \JFactory::getDate();
		$now->setTimeZone($tz);

		$data = $this->_doc;

		$url = Uri::getInstance()->toString(array('scheme', 'user', 'pass', 'host', 'port'));
		$syndicationURL = \JRoute::_('&format=feed&type=atom');

		$title = $data->getTitle();

		if ($app->get('sitename_pagetitles', 0) == 1)
		{
			$title = \JText::sprintf('JPAGETITLE', $app->get('sitename'), $data->getTitle());
		}
		elseif ($app->get('sitename_pagetitles', 0) == 2)
		{
			$title = \JText::sprintf('JPAGETITLE', $data->getTitle(), $app->get('sitename'));
		}

		$feed_title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8');

		$feed = "<feed xmlns=\"http://www.w3.org/2005/Atom\" ";

		if ($data->getLanguage() != '')
		{
			$feed .= " xml:lang=\"" . $data->getLanguage() . "\"";
		}

		$feed .= ">\n";
		$feed .= "	<title type=\"text\">" . $feed_title . "</title>\n";
		$feed .= "	<subtitle type=\"text\">" . htmlspecialchars($data->getDescription(), ENT_COMPAT, 'UTF-8') . "</subtitle>\n";

		if (!empty($data->category))
		{
			if (is_array($data->category))
			{
				foreach ($data->category as $cat)
				{
					$feed .= "	<category term=\"" . htmlspecialchars($cat, ENT_COMPAT, 'UTF-8') . "\" />\n";
				}
			}
			else
			{
				$feed .= "	<category term=\"" . htmlspecialchars($data->category, ENT_COMPAT, 'UTF-8') . "\" />\n";
			}
		}

		$feed .= "	<link rel=\"alternate\" type=\"text/html\" href=\"" . $url . "\"/>\n";
		$feed .= "	<id>" . str_replace(' ', '%20', $data->getBase()) . "</id>\n";
		$feed .= "	<updated>" . htmlspecialchars($now->toISO8601(true), ENT_COMPAT, 'UTF-8') . "</updated>\n";

		if ($data->editor != '')
		{
			$feed .= "	<author>\n";
			$feed .= "		<name>" . $data->editor . "</name>\n";

			if ($data->editorEmail != '')
			{
				$feed .= "		<email>" . htmlspecialchars($data->editorEmail, ENT_COMPAT, 'UTF-8') . "</email>\n";
			}

			$feed .= "	</author>\n";
		}

		$versionHtmlEscaped = '';

		if ($app->get('MetaVersion', 0))
		{
			$minorVersion       = \JVersion::MAJOR_VERSION . '.' . \JVersion::MINOR_VERSION;
			$versionHtmlEscaped = ' version="' . htmlspecialchars($minorVersion, ENT_COMPAT, 'UTF-8') . '"';
		}

		$feed .= "	<generator uri=\"https://www.joomla.org\"" . $versionHtmlEscaped . ">" . $data->getGenerator() . "</generator>\n";
		$feed .= "	<link rel=\"self\" type=\"application/atom+xml\" href=\"" . str_replace(' ', '%20', $url . $syndicationURL) . "\"/>\n";

		for ($i = 0, $count = count($data->items); $i < $count; $i++)
		{
			$itemlink = $data->items[$i]->link;

			if (preg_match('/[\x80-\xFF]/', $itemlink))
			{
				$itemlink = implode('/', array_map('rawurlencode', explode('/', $itemlink)));
			}

			$feed .= "	<entry>\n";
			$feed .= "		<title>" . htmlspecialchars(strip_tags($data->items[$i]->title), ENT_COMPAT, 'UTF-8') . "</title>\n";
			$feed .= "		<link rel=\"alternate\" type=\"text/html\" href=\"" . $url . $itemlink . "\"/>\n";

			if ($data->items[$i]->date == '')
			{
				$data->items[$i]->date = $now->toUnix();
			}

			$itemDate = \JFactory::getDate($data->items[$i]->date);
			$itemDate->setTimeZone($tz);
			$feed .= "		<published>" . htmlspecialchars($itemDate->toISO8601(true), ENT_COMPAT, 'UTF-8') . "</published>\n";
			$feed .= "		<updated>" . htmlspecialchars($itemDate->toISO8601(true), ENT_COMPAT, 'UTF-8') . "</updated>\n";

			if (empty($data->items[$i]->guid))
			{
				$itemGuid = str_replace(' ', '%20', $url . $itemlink);
			}
			else
			{
				$itemGuid = htmlspecialchars($data->items[$i]->guid, ENT_COMPAT, 'UTF-8');
			}

			$feed .= "		<id>" . $itemGuid . "</id>\n";

			if ($data->items[$i]->author != '')
			{
				$feed .= "		<author>\n";
				$feed .= "			<name>" . htmlspecialchars($data->items[$i]->author, ENT_COMPAT, 'UTF-8') . "</name>\n";

				if (!empty($data->items[$i]->authorEmail))
				{
					$feed .= "			<email>" . htmlspecialchars($data->items[$i]->authorEmail, ENT_COMPAT, 'UTF-8') . "</email>\n";
				}

				$feed .= "		</author>\n";
			}

			if (!empty($data->items[$i]->description))
			{
				$feed .= "		<summary type=\"html\">" . htmlspecialchars($this->_relToAbs($data->items[$i]->description), ENT_COMPAT, 'UTF-8') . "</summary>\n";
				$feed .= "		<content type=\"html\">" . htmlspecialchars($this->_relToAbs($data->items[$i]->description), ENT_COMPAT, 'UTF-8') . "</content>\n";
			}

			if (!empty($data->items[$i]->category))
			{
				if (is_array($data->items[$i]->category))
				{
					foreach ($data->items[$i]->category as $cat)
					{
						$feed .= "		<category term=\"" . htmlspecialchars($cat, ENT_COMPAT, 'UTF-8') . "\" />\n";
					}
				}
				else
				{
					$feed .= "		<category term=\"" . htmlspecialchars($data->items[$i]->category, ENT_COMPAT, 'UTF-8') . "\" />\n";
				}
			}

			if ($data->items[$i]->enclosure != null)
			{
				$feed .= "		<link rel=\"enclosure\" href=\"" . $data->items[$i]->enclosure->url . "\" type=\""
					. $data->items[$i]->enclosure->type . "\"  length=\"" . $data->items[$i]->enclosure->length . "\" />\n";
			}

			$feed .= "	</entry>\n";
		}

		$feed .= "</feed>\n";

		return $feed;
	}
}