File indexing completed on 2024-12-22 05:36:40

0001 <?php
0002 
0003 /**
0004  * Zend Framework
0005  *
0006  * LICENSE
0007  *
0008  * This source file is subject to the new BSD license that is bundled
0009  * with this package in the file LICENSE.txt.
0010  * It is also available through the world-wide-web at this URL:
0011  * http://framework.zend.com/license/new-bsd
0012  * If you did not receive a copy of the license and are unable to
0013  * obtain it through the world-wide-web, please send an email
0014  * to license@zend.com so we can send you a copy immediately.
0015  *
0016  * @category   Zend
0017  * @package    Zend_Feed
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 
0024 /**
0025  * @see Zend_Feed_Abstract
0026  */
0027 // require_once 'Zend/Feed/Abstract.php';
0028 
0029 /**
0030  * @see Zend_Feed_Entry_Rss
0031  */
0032 // require_once 'Zend/Feed/Entry/Rss.php';
0033 
0034 
0035 /**
0036  * RSS channel class
0037  *
0038  * The Zend_Feed_Rss class is a concrete subclass of
0039  * Zend_Feed_Abstract meant for representing RSS channels. It does not
0040  * add any methods to its parent, just provides a classname to check
0041  * against with the instanceof operator, and expects to be handling
0042  * RSS-formatted data instead of Atom.
0043  *
0044  * @category   Zend
0045  * @package    Zend_Feed
0046  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0047  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0048  */
0049 class Zend_Feed_Rss extends Zend_Feed_Abstract
0050 {
0051     /**
0052      * The classname for individual channel elements.
0053      *
0054      * @var string
0055      */
0056     protected $_entryClassName = 'Zend_Feed_Entry_Rss';
0057 
0058     /**
0059      * The element name for individual channel elements (RSS <item>s).
0060      *
0061      * @var string
0062      */
0063     protected $_entryElementName = 'item';
0064 
0065     /**
0066      * The default namespace for RSS channels.
0067      *
0068      * @var string
0069      */
0070     protected $_defaultNamespace = 'rss';
0071 
0072     /**
0073      * Override Zend_Feed_Abstract to set up the $_element and $_entries aliases.
0074      *
0075      * @return void
0076      * @throws Zend_Feed_Exception
0077      */
0078     public function __wakeup()
0079     {
0080         parent::__wakeup();
0081 
0082         // Find the base channel element and create an alias to it.
0083         $rdfTags = $this->_element->getElementsByTagNameNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'RDF');
0084         if ($rdfTags->length != 0) {
0085             $this->_element = $rdfTags->item(0);
0086         } else  {
0087             $this->_element = $this->_element->getElementsByTagName('channel')->item(0);
0088         }
0089         if (!$this->_element) {
0090             /**
0091              * @see Zend_Feed_Exception
0092              */
0093             // require_once 'Zend/Feed/Exception.php';
0094             throw new Zend_Feed_Exception('No root <channel> element found, cannot parse channel.');
0095         }
0096 
0097         // Find the entries and save a pointer to them for speed and
0098         // simplicity.
0099         $this->_buildEntryCache();
0100     }
0101 
0102 
0103     /**
0104      * Make accessing some individual elements of the channel easier.
0105      *
0106      * Special accessors 'item' and 'items' are provided so that if
0107      * you wish to iterate over an RSS channel's items, you can do so
0108      * using foreach ($channel->items as $item) or foreach
0109      * ($channel->item as $item).
0110      *
0111      * @param  string $var The property to access.
0112      * @return mixed
0113      */
0114     public function __get($var)
0115     {
0116         switch ($var) {
0117             case 'item':
0118                 // fall through to the next case
0119             case 'items':
0120                 return $this;
0121 
0122             default:
0123                 return parent::__get($var);
0124         }
0125     }
0126 
0127     /**
0128      * Generate the header of the feed when working in write mode
0129      *
0130      * @param  array $array the data to use
0131      * @return DOMElement root node
0132      */
0133     protected function _mapFeedHeaders($array)
0134     {
0135         $channel = $this->_element->createElement('channel');
0136 
0137         $title = $this->_element->createElement('title');
0138         $title->appendChild($this->_element->createCDATASection($array->title));
0139         $channel->appendChild($title);
0140 
0141         $link = $this->_element->createElement('link', $array->link);
0142         $channel->appendChild($link);
0143 
0144         $desc = isset($array->description) ? $array->description : '';
0145         $description = $this->_element->createElement('description');
0146         $description->appendChild($this->_element->createCDATASection($desc));
0147         $channel->appendChild($description);
0148 
0149         $pubdate = isset($array->lastUpdate) ? $array->lastUpdate : time();
0150         $pubdate = $this->_element->createElement('pubDate', date(DATE_RSS, $pubdate));
0151         $channel->appendChild($pubdate);
0152 
0153         if (isset($array->published)) {
0154             $lastBuildDate = $this->_element->createElement('lastBuildDate', date(DATE_RSS, $array->published));
0155             $channel->appendChild($lastBuildDate);
0156         }
0157 
0158         $editor = '';
0159         if (!empty($array->email)) {
0160             $editor .= $array->email;
0161         }
0162         if (!empty($array->author)) {
0163             $editor .= ' (' . $array->author . ')';
0164         }
0165         if (!empty($editor)) {
0166             $author = $this->_element->createElement('managingEditor', ltrim($editor));
0167             $channel->appendChild($author);
0168         }
0169         if (isset($array->webmaster)) {
0170             $channel->appendChild($this->_element->createElement('webMaster', $array->webmaster));
0171         }
0172 
0173         if (!empty($array->copyright)) {
0174             $copyright = $this->_element->createElement('copyright', $array->copyright);
0175             $channel->appendChild($copyright);
0176         }
0177 
0178         if (isset($array->category)) {
0179             $category = $this->_element->createElement('category', $array->category);
0180             $channel->appendChild($category);
0181         }
0182 
0183         if (!empty($array->image)) {
0184             $image = $this->_element->createElement('image');
0185             $url = $this->_element->createElement('url', $array->image);
0186             $image->appendChild($url);
0187             $imagetitle = $this->_element->createElement('title');
0188             $imagetitle->appendChild($this->_element->createCDATASection($array->title));
0189             $image->appendChild($imagetitle);
0190             $imagelink = $this->_element->createElement('link', $array->link);
0191             $image->appendChild($imagelink);
0192 
0193             $channel->appendChild($image);
0194         }
0195 
0196         $generator = !empty($array->generator) ? $array->generator : 'Zend_Feed';
0197         $generator = $this->_element->createElement('generator', $generator);
0198         $channel->appendChild($generator);
0199 
0200         if (!empty($array->language)) {
0201             $language = $this->_element->createElement('language', $array->language);
0202             $channel->appendChild($language);
0203         }
0204 
0205         $doc = $this->_element->createElement('docs', 'http://blogs.law.harvard.edu/tech/rss');
0206         $channel->appendChild($doc);
0207 
0208         if (isset($array->cloud)) {
0209             $cloud = $this->_element->createElement('cloud');
0210             $cloud->setAttribute('domain', $array->cloud['uri']->getHost());
0211             $cloud->setAttribute('port', $array->cloud['uri']->getPort());
0212             $cloud->setAttribute('path', $array->cloud['uri']->getPath());
0213             $cloud->setAttribute('registerProcedure', $array->cloud['procedure']);
0214             $cloud->setAttribute('protocol', $array->cloud['protocol']);
0215             $channel->appendChild($cloud);
0216         }
0217 
0218         if (isset($array->ttl)) {
0219             $ttl = $this->_element->createElement('ttl', $array->ttl);
0220             $channel->appendChild($ttl);
0221         }
0222 
0223         if (isset($array->rating)) {
0224             $rating = $this->_element->createElement('rating', $array->rating);
0225             $channel->appendChild($rating);
0226         }
0227 
0228         if (isset($array->textInput)) {
0229             $textinput = $this->_element->createElement('textInput');
0230             $textinput->appendChild($this->_element->createElement('title', $array->textInput['title']));
0231             $textinput->appendChild($this->_element->createElement('description', $array->textInput['description']));
0232             $textinput->appendChild($this->_element->createElement('name', $array->textInput['name']));
0233             $textinput->appendChild($this->_element->createElement('link', $array->textInput['link']));
0234             $channel->appendChild($textinput);
0235         }
0236 
0237         if (isset($array->skipHours)) {
0238             $skipHours = $this->_element->createElement('skipHours');
0239             foreach ($array->skipHours as $hour) {
0240                 $skipHours->appendChild($this->_element->createElement('hour', $hour));
0241             }
0242             $channel->appendChild($skipHours);
0243         }
0244 
0245         if (isset($array->skipDays)) {
0246             $skipDays = $this->_element->createElement('skipDays');
0247             foreach ($array->skipDays as $day) {
0248                 $skipDays->appendChild($this->_element->createElement('day', $day));
0249             }
0250             $channel->appendChild($skipDays);
0251         }
0252 
0253         if (isset($array->itunes)) {
0254             $this->_buildiTunes($channel, $array);
0255         }
0256 
0257         return $channel;
0258     }
0259 
0260     /**
0261      * Adds the iTunes extensions to a root node
0262      *
0263      * @param  DOMElement $root
0264      * @param  array $array
0265      * @return void
0266      */
0267     private function _buildiTunes(DOMElement $root, $array)
0268     {
0269         /* author node */
0270         $author = '';
0271         if (isset($array->itunes->author)) {
0272             $author = $array->itunes->author;
0273         } elseif (isset($array->author)) {
0274             $author = $array->author;
0275         }
0276         if (!empty($author)) {
0277             $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:author', $author);
0278             $root->appendChild($node);
0279         }
0280 
0281         /* owner node */
0282         $author = '';
0283         $email = '';
0284         if (isset($array->itunes->owner)) {
0285             if (isset($array->itunes->owner['name'])) {
0286                 $author = $array->itunes->owner['name'];
0287             }
0288             if (isset($array->itunes->owner['email'])) {
0289                 $email = $array->itunes->owner['email'];
0290             }
0291         }
0292         if (empty($author) && isset($array->author)) {
0293             $author = $array->author;
0294         }
0295         if (empty($email) && isset($array->email)) {
0296             $email = $array->email;
0297         }
0298         if (!empty($author) || !empty($email)) {
0299             $owner = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:owner');
0300             if (!empty($author)) {
0301                 $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:name', $author);
0302                 $owner->appendChild($node);
0303             }
0304             if (!empty($email)) {
0305                 $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:email', $email);
0306                 $owner->appendChild($node);
0307             }
0308             $root->appendChild($owner);
0309         }
0310         $image = '';
0311         if (isset($array->itunes->image)) {
0312             $image = $array->itunes->image;
0313         } elseif (isset($array->image)) {
0314             $image = $array->image;
0315         }
0316         if (!empty($image)) {
0317             $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:image');
0318             $node->setAttribute('href', $image);
0319             $root->appendChild($node);
0320         }
0321         $subtitle = '';
0322         if (isset($array->itunes->subtitle)) {
0323             $subtitle = $array->itunes->subtitle;
0324         } elseif (isset($array->description)) {
0325             $subtitle = $array->description;
0326         }
0327         if (!empty($subtitle)) {
0328             $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:subtitle', $subtitle);
0329             $root->appendChild($node);
0330         }
0331         $summary = '';
0332         if (isset($array->itunes->summary)) {
0333             $summary = $array->itunes->summary;
0334         } elseif (isset($array->description)) {
0335             $summary = $array->description;
0336         }
0337         if (!empty($summary)) {
0338             $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:summary', $summary);
0339             $root->appendChild($node);
0340         }
0341         if (isset($array->itunes->block)) {
0342             $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:block', $array->itunes->block);
0343             $root->appendChild($node);
0344         }
0345         if (isset($array->itunes->explicit)) {
0346             $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:explicit', $array->itunes->explicit);
0347             $root->appendChild($node);
0348         }
0349         if (isset($array->itunes->keywords)) {
0350             $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:keywords', $array->itunes->keywords);
0351             $root->appendChild($node);
0352         }
0353         if (isset($array->itunes->new_feed_url)) {
0354             $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:new-feed-url', $array->itunes->new_feed_url);
0355             $root->appendChild($node);
0356         }
0357         if (isset($array->itunes->category)) {
0358             foreach ($array->itunes->category as $i => $category) {
0359                 $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:category');
0360                 $node->setAttribute('text', $category['main']);
0361                 $root->appendChild($node);
0362                 $add_end_category = false;
0363                 if (!empty($category['sub'])) {
0364                     $add_end_category = true;
0365                     $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:category');
0366                     $node->setAttribute('text', $category['sub']);
0367                     $root->appendChild($node);
0368                 }
0369                 if ($i > 0 || $add_end_category) {
0370                     $node = $this->_element->createElementNS('http://www.itunes.com/DTDs/Podcast-1.0.dtd', 'itunes:category');
0371                     $root->appendChild($node);
0372                 }
0373             }
0374         }
0375     }
0376 
0377     /**
0378      * Generate the entries of the feed when working in write mode
0379      *
0380      * The following nodes are constructed for each feed entry
0381      * <item>
0382      *    <title>entry title</title>
0383      *    <link>url to feed entry</link>
0384      *    <guid>url to feed entry</guid>
0385      *    <description>short text</description>
0386      *    <content:encoded>long version, can contain html</content:encoded>
0387      * </item>
0388      *
0389      * @param  DOMElement $root the root node to use
0390      * @param  array $array the data to use
0391      * @return void
0392      */
0393     protected function _mapFeedEntries(DOMElement $root, $array)
0394     {
0395         Zend_Feed::registerNamespace('content', 'http://purl.org/rss/1.0/modules/content/');
0396 
0397         foreach ($array as $dataentry) {
0398             $item = $this->_element->createElement('item');
0399 
0400             $title = $this->_element->createElement('title');
0401             $title->appendChild($this->_element->createCDATASection($dataentry->title));
0402             $item->appendChild($title);
0403 
0404             if (isset($dataentry->author)) {
0405                 $author = $this->_element->createElement('author', $dataentry->author);
0406                 $item->appendChild($author);
0407             }
0408 
0409             $link = $this->_element->createElement('link', $dataentry->link);
0410             $item->appendChild($link);
0411 
0412             if (isset($dataentry->guid)) {
0413                 $guid = $this->_element->createElement('guid', $dataentry->guid);
0414                 if (!Zend_Uri::check($dataentry->guid)) {
0415                     $guid->setAttribute('isPermaLink', 'false');
0416                 }
0417                 $item->appendChild($guid);
0418             }
0419 
0420             $description = $this->_element->createElement('description');
0421             $description->appendChild($this->_element->createCDATASection($dataentry->description));
0422             $item->appendChild($description);
0423 
0424             if (isset($dataentry->content)) {
0425                 $content = $this->_element->createElement('content:encoded');
0426                 $content->appendChild($this->_element->createCDATASection($dataentry->content));
0427                 $item->appendChild($content);
0428             }
0429 
0430             $pubdate = isset($dataentry->lastUpdate) ? $dataentry->lastUpdate : time();
0431             $pubdate = $this->_element->createElement('pubDate', date(DATE_RSS, $pubdate));
0432             $item->appendChild($pubdate);
0433 
0434             if (isset($dataentry->category)) {
0435                 foreach ($dataentry->category as $category) {
0436                     $node = $this->_element->createElement('category');
0437                     $node->appendChild($this->_element->createCDATASection($category['term']));
0438                     if (isset($category['scheme'])) {
0439                         $node->setAttribute('domain', $category['scheme']);
0440                     }
0441                     $item->appendChild($node);
0442                 }
0443             }
0444 
0445             if (isset($dataentry->source)) {
0446                 $source = $this->_element->createElement('source', $dataentry->source['title']);
0447                 $source->setAttribute('url', $dataentry->source['url']);
0448                 $item->appendChild($source);
0449             }
0450 
0451             if (isset($dataentry->comments)) {
0452                 $comments = $this->_element->createElement('comments', $dataentry->comments);
0453                 $item->appendChild($comments);
0454             }
0455             if (isset($dataentry->commentRss)) {
0456                 $comments = $this->_element->createElementNS('http://wellformedweb.org/CommentAPI/',
0457                                                              'wfw:commentRss',
0458                                                              $dataentry->commentRss);
0459                 $item->appendChild($comments);
0460             }
0461 
0462 
0463             if (isset($dataentry->enclosure)) {
0464                 foreach ($dataentry->enclosure as $enclosure) {
0465                     $node = $this->_element->createElement('enclosure');
0466                     $node->setAttribute('url', $enclosure['url']);
0467                     if (isset($enclosure['type'])) {
0468                         $node->setAttribute('type', $enclosure['type']);
0469                     }
0470                     if (isset($enclosure['length'])) {
0471                         $node->setAttribute('length', $enclosure['length']);
0472                     }
0473                     $item->appendChild($node);
0474                 }
0475             }
0476 
0477             $root->appendChild($item);
0478         }
0479     }
0480 
0481     /**
0482      * Override Zend_Feed_Element to include <rss> root node
0483      *
0484      * @return string
0485      */
0486     public function saveXml()
0487     {
0488         // Return a complete document including XML prologue.
0489         $doc = new DOMDocument($this->_element->ownerDocument->version,
0490                                $this->_element->ownerDocument->actualEncoding);
0491         $root = $doc->createElement('rss');
0492 
0493         // Use rss version 2.0
0494         $root->setAttribute('version', '2.0');
0495 
0496         // Content namespace
0497         $root->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:content', 'http://purl.org/rss/1.0/modules/content/');
0498         $root->appendChild($doc->importNode($this->_element, true));
0499 
0500         // Append root node
0501         $doc->appendChild($root);
0502 
0503         // Format output
0504         $doc->formatOutput = true;
0505 
0506         return $doc->saveXML();
0507     }
0508 
0509     /**
0510      * Send feed to a http client with the correct header
0511      *
0512      * @return void
0513      * @throws Zend_Feed_Exception if headers have already been sent
0514      */
0515     public function send()
0516     {
0517         if (headers_sent()) {
0518             /**
0519              * @see Zend_Feed_Exception
0520              */
0521             // require_once 'Zend/Feed/Exception.php';
0522             throw new Zend_Feed_Exception('Cannot send RSS because headers have already been sent.');
0523         }
0524 
0525         header('Content-Type: application/rss+xml; charset=' . $this->_element->ownerDocument->actualEncoding);
0526 
0527         echo $this->saveXml();
0528     }
0529 
0530 }