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 }