| <?php |
| /** |
| * Zend Framework |
| * |
| * LICENSE |
| * |
| * This source file is subject to the new BSD license that is bundled |
| * with this package in the file LICENSE.txt. |
| * It is also available through the world-wide-web at this URL: |
| * http://framework.zend.com/license/new-bsd |
| * If you did not receive a copy of the license and are unable to |
| * obtain it through the world-wide-web, please send an email |
| * to license@zend.com so we can send you a copy immediately. |
| * |
| * @category Zend |
| * @package Zend_Feed |
| * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) |
| * @license http://framework.zend.com/license/new-bsd New BSD License |
| * @version $Id: Rss.php 8064 2008-02-16 10:58:39Z thomas $ |
| */ |
| |
| /** |
| * @see Zend_Feed_Abstract |
| */ |
| require_once 'external/Zend/Feed/Abstract.php'; |
| |
| /** |
| * @see Zend_Feed_Entry_Rss |
| */ |
| require_once 'external/Zend/Feed/Entry/Rss.php'; |
| |
| /** |
| * RSS channel class |
| * |
| * The Zend_Feed_Rss class is a concrete subclass of |
| * Zend_Feed_Abstract meant for representing RSS channels. It does not |
| * add any methods to its parent, just provides a classname to check |
| * against with the instanceof operator, and expects to be handling |
| * RSS-formatted data instead of Atom. |
| * |
| * @category Zend |
| * @package Zend_Feed |
| * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) |
| * @license http://framework.zend.com/license/new-bsd New BSD License |
| */ |
| class Zend_Feed_Rss extends Zend_Feed_Abstract { |
| /** |
| * The classname for individual channel elements. |
| * |
| * @var string |
| */ |
| protected $_entryClassName = 'Zend_Feed_Entry_Rss'; |
| |
| /** |
| * The element name for individual channel elements (RSS <item>s). |
| * |
| * @var string |
| */ |
| protected $_entryElementName = 'item'; |
| |
| /** |
| * The default namespace for RSS channels. |
| * |
| * @var string |
| */ |
| protected $_defaultNamespace = 'rss'; |
| |
| /** |
| * Override Zend_Feed_Abstract to set up the $_element and $_entries aliases. |
| * |
| * @return void |
| * @throws Zend_Feed_Exception |
| */ |
| public function __wakeup() { |
| parent::__wakeup(); |
| |
| // Find the base channel element and create an alias to it. |
| $rdf = $this->_element->getElementsByTagNameNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'RDF')->item(0); |
| if ($rdf) { |
| $this->_element = $rdf; |
| $channel = $this->_element->getElementsByTagName('channel')->item(0); |
| if ($channel->getElementsByTagName('title')->item(0)) |
| $this->_element->appendChild($channel->getElementsByTagName('title')->item(0)); |
| if ($channel->getElementsByTagName('link')->item(0)) |
| $this->_element->appendChild($channel->getElementsByTagName('link')->item(0)); |
| if ($channel->getElementsByTagName('description')->item(0)) |
| $this->_element->appendChild($channel->getElementsByTagName('description')->item(0)); |
| } else { |
| $this->_element = $this->_element->getElementsByTagName('channel')->item(0); |
| } |
| if (! $this->_element) { |
| /** |
| * @see Zend_Feed_Exception |
| */ |
| require_once 'external/Zend/Feed/Exception.php'; |
| throw new Zend_Feed_Exception('No root <channel> element found, cannot parse channel.'); |
| } |
| |
| // Find the entries and save a pointer to them for speed and |
| // simplicity. |
| $this->_buildEntryCache(); |
| } |
| |
| /** |
| * Make accessing some individual elements of the channel easier. |
| * |
| * Special accessors 'item' and 'items' are provided so that if |
| * you wish to iterate over an RSS channel's items, you can do so |
| * using foreach ($channel->items as $item) or foreach |
| * ($channel->item as $item). |
| * |
| * @param string $var The property to access. |
| * @return mixed |
| */ |
| public function __get($var) { |
| switch ($var) { |
| case 'item': |
| // fall through to the next case |
| case 'items': |
| return $this; |
| |
| default: |
| return parent::__get($var); |
| } |
| } |
| |
| /** |
| * Generate the header of the feed when working in write mode |
| * |
| * @param array $array the data to use |
| * @return DOMElement root node |
| */ |
| protected function _mapFeedHeaders($array) { |
| $channel = $this->_element->createElement('channel'); |
| |
| $title = $this->_element->createElement('title'); |
| $title->appendChild($this->_element->createCDATASection($array->title)); |
| $channel->appendChild($title); |
| |
| $link = $this->_element->createElement('link', $array->link); |
| $channel->appendChild($link); |
| |
| $desc = isset($array->description) ? $array->description : ''; |
| $description = $this->_element->createElement('description'); |
| $description->appendChild($this->_element->createCDATASection($desc)); |
| $channel->appendChild($description); |
| |
| $pubdate = isset($array->lastUpdate) ? $array->lastUpdate : time(); |
| $pubdate = $this->_element->createElement('pubDate', gmdate('r', $pubdate)); |
| $channel->appendChild($pubdate); |
| |
| if (isset($array->published)) { |
| $lastBuildDate = $this->_element->createElement('lastBuildDate', gmdate('r', $array->published)); |
| } |
| |
| $editor = ''; |
| if (! empty($array->email)) { |
| $editor .= $array->email; |
| } |
| if (! empty($array->author)) { |
| $editor .= ' (' . $array->author . ')'; |
| } |
| if (! empty($editor)) { |
| $author = $this->_element->createElement('managingEditor', ltrim($editor)); |
| $channel->appendChild($author); |
| } |
| if (isset($array->webmaster)) { |
| $channel->appendChild($this->_element->createElement('webMaster', $array->webmaster)); |
| } |
| |
| if (! empty($array->copyright)) { |
| $copyright = $this->_element->createElement('copyright', $array->copyright); |
| $channel->appendChild($copyright); |
| } |
| |
| if (! empty($array->image)) { |
| $image = $this->_element->createElement('image'); |
| $url = $this->_element->createElement('url', $array->image); |
| $image->appendChild($url); |
| $imagetitle = $this->_element->createElement('title', $array->title); |
| $image->appendChild($imagetitle); |
| $imagelink = $this->_element->createElement('link', $array->link); |
| $image->appendChild($imagelink); |
| |
| $channel->appendChild($image); |
| } |
| |
| $generator = ! empty($array->generator) ? $array->generator : 'Zend_Feed'; |
| $generator = $this->_element->createElement('generator', $generator); |
| $channel->appendChild($generator); |
| |
| if (! empty($array->language)) { |
| $language = $this->_element->createElement('language', $array->language); |
| $channel->appendChild($language); |
| } |
| |
| $doc = $this->_element->createElement('docs', 'http://blogs.law.harvard.edu/tech/rss'); |
| $channel->appendChild($doc); |
| |
| if (isset($array->cloud)) { |
| $cloud = $this->_element->createElement('cloud'); |
| $cloud->setAttribute('domain', $array->cloud['uri']->getHost()); |
| $cloud->setAttribute('port', $array->cloud['uri']->getPort()); |
| $cloud->setAttribute('path', $array->cloud['uri']->getPath()); |
| $cloud->setAttribute('registerProcedure', $array->cloud['procedure']); |
| $cloud->setAttribute('protocol', $array->cloud['protocol']); |
| $channel->appendChild($cloud); |
| } |
| |
| if (isset($array->rating)) { |
| $rating = $this->_element->createElement('rating', $array->rating); |
| $channel->appendChild($rating); |
| } |
| |
| if (isset($array->textInput)) { |
| $textinput = $this->_element->createElement('textInput'); |
| $textinput->appendChild($this->_element->createElement('title', $array->textInput['title'])); |
| $textinput->appendChild($this->_element->createElement('description', $array->textInput['description'])); |
| $textinput->appendChild($this->_element->createElement('name', $array->textInput['name'])); |
| $textinput->appendChild($this->_element->createElement('link', $array->textInput['link'])); |
| $channel->appendChild($textinput); |
| } |
| |
| if (isset($array->skipHours)) { |
| $skipHours = $this->_element->createElement('skipHours'); |
| foreach ($array->skipHours as $hour) { |
| $skipHours->appendChild($this->_element->createElement('hour', $hour)); |
| } |
| $channel->appendChild($skipHours); |
| } |
| |
| if (isset($array->skipDays)) { |
| $skipDays = $this->_element->createElement('skipDays'); |
| foreach ($array->skipDays as $day) { |
| $skipDays->appendChild($this->_element->createElement('day', $day)); |
| } |
| $channel->appendChild($skipDays); |
| } |
| |
| if (isset($array->itunes)) { |
| $this->_buildiTunes($channel, $array); |
| } |
| |
| return $channel; |
| } |
| |
| /** |
| * Adds the iTunes extensions to a root node |
| * |
| * @param DOMElement $root |
| * @param array $array |
| * @return void |
| */ |
| private function _buildiTunes(DOMElement $root, $array) { |
| /* author node */ |
| $author = ''; |
| if (isset($array->itunes->author)) { |
| $author = $array->itunes->author; |
| } elseif (isset($array->author)) { |
| $author = $array->author; |
| } |
| if (! empty($author)) { |
| $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:author', $author); |
| $root->appendChild($node); |
| } |
| |
| /* owner node */ |
| $author = ''; |
| $email = ''; |
| if (isset($array->itunes->owner)) { |
| if (isset($array->itunes->owner['name'])) { |
| $author = $array->itunes->owner['name']; |
| } |
| if (isset($array->itunes->owner['email'])) { |
| $email = $array->itunes->owner['email']; |
| } |
| } |
| if (empty($author) && isset($array->author)) { |
| $author = $array->author; |
| } |
| if (empty($email) && isset($array->email)) { |
| $email = $array->email; |
| } |
| if (! empty($author) || ! empty($email)) { |
| $owner = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:owner'); |
| if (! empty($author)) { |
| $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:name', $author); |
| $owner->appendChild($node); |
| } |
| if (! empty($email)) { |
| $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:email', $email); |
| $owner->appendChild($node); |
| } |
| $root->appendChild($owner); |
| } |
| $image = ''; |
| if (isset($array->itunes->image)) { |
| $image = $array->itunes->image; |
| } elseif (isset($array->image)) { |
| $image = $array->image; |
| } |
| if (! empty($image)) { |
| $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:image'); |
| $node->setAttribute('href', $image); |
| $root->appendChild($node); |
| } |
| $subtitle = ''; |
| if (isset($array->itunes->subtitle)) { |
| $subtitle = $array->itunes->subtitle; |
| } elseif (isset($array->description)) { |
| $subtitle = $array->description; |
| } |
| if (! empty($subtitle)) { |
| $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:subtitle', $subtitle); |
| $root->appendChild($node); |
| } |
| $summary = ''; |
| if (isset($array->itunes->summary)) { |
| $summary = $array->itunes->summary; |
| } elseif (isset($array->description)) { |
| $summary = $array->description; |
| } |
| if (! empty($summary)) { |
| $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:summary', $summary); |
| $root->appendChild($node); |
| } |
| if (isset($array->itunes->block)) { |
| $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:block', $array->itunes->block); |
| $root->appendChild($node); |
| } |
| if (isset($array->itunes->explicit)) { |
| $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:explicit', $array->itunes->explicit); |
| $root->appendChild($node); |
| } |
| if (isset($array->itunes->keywords)) { |
| $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:keywords', $array->itunes->keywords); |
| $root->appendChild($node); |
| } |
| if (isset($array->itunes->new_feed_url)) { |
| $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:new-feed-url', $array->itunes->new_feed_url); |
| $root->appendChild($node); |
| } |
| if (isset($array->itunes->category)) { |
| foreach ($array->itunes->category as $i => $category) { |
| $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:category'); |
| $node->setAttribute('text', $category['main']); |
| $root->appendChild($node); |
| $add_end_category = false; |
| if (! empty($category['sub'])) { |
| $add_end_category = true; |
| $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:category'); |
| $node->setAttribute('text', $category['sub']); |
| $root->appendChild($node); |
| } |
| if ($i > 0 || $add_end_category) { |
| $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:category'); |
| $root->appendChild($node); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Generate the entries of the feed when working in write mode |
| * |
| * The following nodes are constructed for each feed entry |
| * <item> |
| * <title>entry title</title> |
| * <link>url to feed entry</link> |
| * <guid>url to feed entry</guid> |
| * <description>short text</description> |
| * <content:encoded>long version, can contain html</content:encoded> |
| * </item> |
| * |
| * @param DOMElement $root the root node to use |
| * @param array $array the data to use |
| * @return void |
| */ |
| protected function _mapFeedEntries(DOMElement $root, $array) { |
| Zend_Feed::registerNamespace('content', 'http://purl.org/rss/1.0/modules/content/'); |
| |
| foreach ($array as $dataentry) { |
| $item = $this->_element->createElement('item'); |
| |
| $title = $this->_element->createElement('title'); |
| $title->appendChild($this->_element->createCDATASection($dataentry->title)); |
| $item->appendChild($title); |
| |
| $link = $this->_element->createElement('link', $dataentry->link); |
| $item->appendChild($link); |
| |
| if (isset($dataentry->guid)) { |
| $guid = $this->_element->createElement('guid', $dataentry->guid); |
| $item->appendChild($guid); |
| } |
| |
| $description = $this->_element->createElement('description'); |
| $description->appendChild($this->_element->createCDATASection($dataentry->description)); |
| $item->appendChild($description); |
| |
| if (isset($dataentry->content)) { |
| $content = $this->_element->createElement('content:encoded'); |
| $content->appendChild($this->_element->createCDATASection($dataentry->content)); |
| $item->appendChild($content); |
| } |
| |
| $pubdate = isset($dataentry->lastUpdate) ? $dataentry->lastUpdate : time(); |
| $pubdate = $this->_element->createElement('pubDate', gmdate('r', $pubdate)); |
| $item->appendChild($pubdate); |
| |
| if (isset($dataentry->category)) { |
| foreach ($dataentry->category as $category) { |
| $node = $this->_element->createElement('category', $category['term']); |
| if (isset($category['scheme'])) { |
| $node->setAttribute('domain', $category['scheme']); |
| } |
| $item->appendChild($node); |
| } |
| } |
| |
| if (isset($dataentry->source)) { |
| $source = $this->_element->createElement('source', $dataentry->source['title']); |
| $source->setAttribute('url', $dataentry->source['url']); |
| $item->appendChild($source); |
| } |
| |
| if (isset($dataentry->comments)) { |
| $comments = $this->_element->createElement('comments', $dataentry->comments); |
| $item->appendChild($comments); |
| } |
| if (isset($dataentry->commentRss)) { |
| $comments = $this->_element->createElementNS('http://wellformedweb.org/CommentAPI/', 'wfw:commentRss', $dataentry->commentRss); |
| $item->appendChild($comments); |
| } |
| |
| if (isset($dataentry->enclosure)) { |
| foreach ($dataentry->enclosure as $enclosure) { |
| $node = $this->_element->createElement('enclosure'); |
| $node->setAttribute('url', $enclosure['url']); |
| if (isset($enclosure['type'])) { |
| $node->setAttribute('type', $enclosure['type']); |
| } |
| if (isset($enclosure['length'])) { |
| $node->setAttribute('length', $enclosure['length']); |
| } |
| $item->appendChild($node); |
| } |
| } |
| |
| $root->appendChild($item); |
| } |
| } |
| |
| /** |
| * Override Zend_Feed_Element to include <rss> root node |
| * |
| * @return string |
| */ |
| public function saveXml() { |
| // Return a complete document including XML prologue. |
| $doc = new DOMDocument($this->_element->ownerDocument->version, $this->_element->ownerDocument->actualEncoding); |
| $root = $doc->createElement('rss'); |
| |
| // Use rss version 2.0 |
| $root->setAttribute('version', '2.0'); |
| |
| // Content namespace |
| $root->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:content', 'http://purl.org/rss/1.0/modules/content/'); |
| $root->appendChild($doc->importNode($this->_element, true)); |
| |
| // Append root node |
| $doc->appendChild($root); |
| |
| // Format output |
| $doc->formatOutput = true; |
| |
| return $doc->saveXML(); |
| } |
| |
| /** |
| * Send feed to a http client with the correct header |
| * |
| * @return void |
| * @throws Zend_Feed_Exception if headers have already been sent |
| */ |
| public function send() { |
| if (headers_sent()) { |
| /** |
| * @see Zend_Feed_Exception |
| */ |
| require_once 'external/Zend/Feed/Exception.php'; |
| throw new Zend_Feed_Exception('Cannot send RSS because headers have already been sent.'); |
| } |
| |
| header('Content-type: application/rss+xml; charset: ' . $this->_element->ownerDocument->actualEncoding); |
| |
| echo $this->saveXml(); |
| } |
| |
| } |