File indexing completed on 2025-01-19 05:21:05
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Feed_Reader 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** 0023 * @see Zend_Feed_Reader 0024 */ 0025 // require_once 'Zend/Feed/Reader.php'; 0026 0027 /** 0028 * @see Zend_Feed_Reader_Extension_EntryAbstract 0029 */ 0030 // require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; 0031 0032 /** 0033 * @see Zend_Date 0034 */ 0035 // require_once 'Zend/Date.php'; 0036 0037 /** 0038 * @see Zend_Uri 0039 */ 0040 // require_once 'Zend/Uri.php'; 0041 0042 /** 0043 * @see Zend_Feed_Reader_Collection_Category 0044 */ 0045 // require_once 'Zend/Feed/Reader/Collection/Category.php'; 0046 0047 /** 0048 * @see Zend_Feed_Reader_Feed_Atom_Source 0049 */ 0050 // require_once 'Zend/Feed/Reader/Feed/Atom/Source.php'; 0051 0052 /** 0053 * @category Zend 0054 * @package Zend_Feed_Reader 0055 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0056 * @license http://framework.zend.com/license/new-bsd New BSD License 0057 */ 0058 class Zend_Feed_Reader_Extension_Atom_Entry 0059 extends Zend_Feed_Reader_Extension_EntryAbstract 0060 { 0061 /** 0062 * Get the specified author 0063 * 0064 * @param int $index 0065 * @return string|null 0066 */ 0067 public function getAuthor($index = 0) 0068 { 0069 $authors = $this->getAuthors(); 0070 0071 if (isset($authors[$index])) { 0072 return $authors[$index]; 0073 } 0074 0075 return null; 0076 } 0077 0078 /** 0079 * Get an array with feed authors 0080 * 0081 * @return array 0082 */ 0083 public function getAuthors() 0084 { 0085 if (array_key_exists('authors', $this->_data)) { 0086 return $this->_data['authors']; 0087 } 0088 0089 $authors = array(); 0090 $list = $this->getXpath()->query($this->getXpathPrefix() . '//atom:author'); 0091 0092 if (!$list->length) { 0093 /** 0094 * TODO: Limit query to feed level els only! 0095 */ 0096 $list = $this->getXpath()->query('//atom:author'); 0097 } 0098 0099 if ($list->length) { 0100 foreach ($list as $author) { 0101 $author = $this->_getAuthor($author); 0102 if (!empty($author)) { 0103 $authors[] = $author; 0104 } 0105 } 0106 } 0107 0108 if (count($authors) == 0) { 0109 $authors = null; 0110 } else { 0111 $authors = new Zend_Feed_Reader_Collection_Author( 0112 Zend_Feed_Reader::arrayUnique($authors) 0113 ); 0114 } 0115 0116 $this->_data['authors'] = $authors; 0117 return $this->_data['authors']; 0118 } 0119 0120 /** 0121 * Get the entry content 0122 * 0123 * @return string 0124 */ 0125 public function getContent() 0126 { 0127 if (array_key_exists('content', $this->_data)) { 0128 return $this->_data['content']; 0129 } 0130 0131 $content = null; 0132 0133 $el = $this->getXpath()->query($this->getXpathPrefix() . '/atom:content'); 0134 if($el->length > 0) { 0135 $el = $el->item(0); 0136 $type = $el->getAttribute('type'); 0137 switch ($type) { 0138 case '': 0139 case 'text': 0140 case 'text/plain': 0141 case 'html': 0142 case 'text/html': 0143 $content = $el->nodeValue; 0144 break; 0145 case 'xhtml': 0146 $this->getXpath()->registerNamespace('xhtml', 'http://www.w3.org/1999/xhtml'); 0147 $xhtml = $this->getXpath()->query( 0148 $this->getXpathPrefix() . '/atom:content/xhtml:div' 0149 )->item(0); 0150 //$xhtml->setAttribute('xmlns', 'http://www.w3.org/1999/xhtml'); 0151 $d = new DOMDocument('1.0', $this->getEncoding()); 0152 $xhtmls = $d->importNode($xhtml, true); 0153 $d->appendChild($xhtmls); 0154 $content = $this->_collectXhtml( 0155 $d->saveXML(), 0156 $d->lookupPrefix('http://www.w3.org/1999/xhtml') 0157 ); 0158 break; 0159 } 0160 } 0161 0162 if (!$content) { 0163 $content = $this->getDescription(); 0164 } 0165 0166 $this->_data['content'] = trim($content); 0167 0168 return $this->_data['content']; 0169 } 0170 0171 /** 0172 * Parse out XHTML to remove the namespacing 0173 */ 0174 protected function _collectXhtml($xhtml, $prefix) 0175 { 0176 if (!empty($prefix)) $prefix = $prefix . ':'; 0177 $matches = array( 0178 "/<\?xml[^<]*>[^<]*<" . $prefix . "div[^<]*/", 0179 "/<\/" . $prefix . "div>\s*$/" 0180 ); 0181 $xhtml = preg_replace($matches, '', $xhtml); 0182 if (!empty($prefix)) { 0183 $xhtml = preg_replace("/(<[\/]?)" . $prefix . "([a-zA-Z]+)/", '$1$2', $xhtml); 0184 } 0185 return $xhtml; 0186 } 0187 0188 /** 0189 * Get the entry creation date 0190 * 0191 * @return string 0192 */ 0193 public function getDateCreated() 0194 { 0195 if (array_key_exists('datecreated', $this->_data)) { 0196 return $this->_data['datecreated']; 0197 } 0198 0199 $date = null; 0200 0201 if ($this->_getAtomType() === Zend_Feed_Reader::TYPE_ATOM_03) { 0202 $dateCreated = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:created)'); 0203 } else { 0204 $dateCreated = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:published)'); 0205 } 0206 0207 if ($dateCreated) { 0208 $date = new Zend_Date; 0209 $date->set($dateCreated, Zend_Date::ISO_8601); 0210 } 0211 0212 $this->_data['datecreated'] = $date; 0213 0214 return $this->_data['datecreated']; 0215 } 0216 0217 /** 0218 * Get the entry modification date 0219 * 0220 * @return string 0221 */ 0222 public function getDateModified() 0223 { 0224 if (array_key_exists('datemodified', $this->_data)) { 0225 return $this->_data['datemodified']; 0226 } 0227 0228 $date = null; 0229 0230 if ($this->_getAtomType() === Zend_Feed_Reader::TYPE_ATOM_03) { 0231 $dateModified = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:modified)'); 0232 } else { 0233 $dateModified = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:updated)'); 0234 } 0235 0236 if ($dateModified) { 0237 $date = new Zend_Date; 0238 $date->set($dateModified, Zend_Date::ISO_8601); 0239 } 0240 0241 $this->_data['datemodified'] = $date; 0242 0243 return $this->_data['datemodified']; 0244 } 0245 0246 /** 0247 * Get the entry description 0248 * 0249 * @return string 0250 */ 0251 public function getDescription() 0252 { 0253 if (array_key_exists('description', $this->_data)) { 0254 return $this->_data['description']; 0255 } 0256 0257 $description = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:summary)'); 0258 0259 if (!$description) { 0260 $description = null; 0261 } 0262 0263 $this->_data['description'] = $description; 0264 0265 return $this->_data['description']; 0266 } 0267 0268 /** 0269 * Get the entry enclosure 0270 * 0271 * @return string 0272 */ 0273 public function getEnclosure() 0274 { 0275 if (array_key_exists('enclosure', $this->_data)) { 0276 return $this->_data['enclosure']; 0277 } 0278 0279 $enclosure = null; 0280 0281 $nodeList = $this->getXpath()->query($this->getXpathPrefix() . '/atom:link[@rel="enclosure"]'); 0282 0283 if ($nodeList->length > 0) { 0284 $enclosure = new stdClass(); 0285 $enclosure->url = $nodeList->item(0)->getAttribute('href'); 0286 $enclosure->length = $nodeList->item(0)->getAttribute('length'); 0287 $enclosure->type = $nodeList->item(0)->getAttribute('type'); 0288 } 0289 0290 $this->_data['enclosure'] = $enclosure; 0291 0292 return $this->_data['enclosure']; 0293 } 0294 0295 /** 0296 * Get the entry ID 0297 * 0298 * @return string 0299 */ 0300 public function getId() 0301 { 0302 if (array_key_exists('id', $this->_data)) { 0303 return $this->_data['id']; 0304 } 0305 0306 $id = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:id)'); 0307 0308 if (!$id) { 0309 if ($this->getPermalink()) { 0310 $id = $this->getPermalink(); 0311 } elseif ($this->getTitle()) { 0312 $id = $this->getTitle(); 0313 } else { 0314 $id = null; 0315 } 0316 } 0317 0318 $this->_data['id'] = $id; 0319 0320 return $this->_data['id']; 0321 } 0322 0323 /** 0324 * Get the base URI of the feed (if set). 0325 * 0326 * @return string|null 0327 */ 0328 public function getBaseUrl() 0329 { 0330 if (array_key_exists('baseUrl', $this->_data)) { 0331 return $this->_data['baseUrl']; 0332 } 0333 0334 $baseUrl = $this->getXpath()->evaluate('string(' 0335 . $this->getXpathPrefix() . '/@xml:base[1]' 0336 . ')'); 0337 0338 if (!$baseUrl) { 0339 $baseUrl = $this->getXpath()->evaluate('string(//@xml:base[1])'); 0340 } 0341 0342 if (!$baseUrl) { 0343 $baseUrl = null; 0344 } 0345 0346 $this->_data['baseUrl'] = $baseUrl; 0347 0348 return $this->_data['baseUrl']; 0349 } 0350 0351 /** 0352 * Get a specific link 0353 * 0354 * @param int $index 0355 * @return string 0356 */ 0357 public function getLink($index = 0) 0358 { 0359 if (!array_key_exists('links', $this->_data)) { 0360 $this->getLinks(); 0361 } 0362 0363 if (isset($this->_data['links'][$index])) { 0364 return $this->_data['links'][$index]; 0365 } 0366 0367 return null; 0368 } 0369 0370 /** 0371 * Get all links 0372 * 0373 * @return array 0374 */ 0375 public function getLinks() 0376 { 0377 if (array_key_exists('links', $this->_data)) { 0378 return $this->_data['links']; 0379 } 0380 0381 $links = array(); 0382 0383 $list = $this->getXpath()->query( 0384 $this->getXpathPrefix() . '//atom:link[@rel="alternate"]/@href' . '|' . 0385 $this->getXpathPrefix() . '//atom:link[not(@rel)]/@href' 0386 ); 0387 0388 if ($list->length) { 0389 foreach ($list as $link) { 0390 $links[] = $this->_absolutiseUri($link->value); 0391 } 0392 } 0393 0394 $this->_data['links'] = $links; 0395 0396 return $this->_data['links']; 0397 } 0398 0399 /** 0400 * Get a permalink to the entry 0401 * 0402 * @return string 0403 */ 0404 public function getPermalink() 0405 { 0406 return $this->getLink(0); 0407 } 0408 0409 /** 0410 * Get the entry title 0411 * 0412 * @return string 0413 */ 0414 public function getTitle() 0415 { 0416 if (array_key_exists('title', $this->_data)) { 0417 return $this->_data['title']; 0418 } 0419 0420 $title = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:title)'); 0421 0422 if (!$title) { 0423 $title = null; 0424 } 0425 0426 $this->_data['title'] = $title; 0427 0428 return $this->_data['title']; 0429 } 0430 0431 /** 0432 * Get the number of comments/replies for current entry 0433 * 0434 * @return integer 0435 */ 0436 public function getCommentCount() 0437 { 0438 if (array_key_exists('commentcount', $this->_data)) { 0439 return $this->_data['commentcount']; 0440 } 0441 0442 $count = null; 0443 0444 $this->getXpath()->registerNamespace('thread10', 'http://purl.org/syndication/thread/1.0'); 0445 $list = $this->getXpath()->query( 0446 $this->getXpathPrefix() . '//atom:link[@rel="replies"]/@thread10:count' 0447 ); 0448 0449 if ($list->length) { 0450 $count = $list->item(0)->value; 0451 } 0452 0453 $this->_data['commentcount'] = $count; 0454 0455 return $this->_data['commentcount']; 0456 } 0457 0458 /** 0459 * Returns a URI pointing to the HTML page where comments can be made on this entry 0460 * 0461 * @return string 0462 */ 0463 public function getCommentLink() 0464 { 0465 if (array_key_exists('commentlink', $this->_data)) { 0466 return $this->_data['commentlink']; 0467 } 0468 0469 $link = null; 0470 0471 $list = $this->getXpath()->query( 0472 $this->getXpathPrefix() . '//atom:link[@rel="replies" and @type="text/html"]/@href' 0473 ); 0474 0475 if ($list->length) { 0476 $link = $list->item(0)->value; 0477 $link = $this->_absolutiseUri($link); 0478 } 0479 0480 $this->_data['commentlink'] = $link; 0481 0482 return $this->_data['commentlink']; 0483 } 0484 0485 /** 0486 * Returns a URI pointing to a feed of all comments for this entry 0487 * 0488 * @return string 0489 */ 0490 public function getCommentFeedLink($type = 'atom') 0491 { 0492 if (array_key_exists('commentfeedlink', $this->_data)) { 0493 return $this->_data['commentfeedlink']; 0494 } 0495 0496 $link = null; 0497 0498 $list = $this->getXpath()->query( 0499 $this->getXpathPrefix() . '//atom:link[@rel="replies" and @type="application/'.$type.'+xml"]/@href' 0500 ); 0501 0502 if ($list->length) { 0503 $link = $list->item(0)->value; 0504 $link = $this->_absolutiseUri($link); 0505 } 0506 0507 $this->_data['commentfeedlink'] = $link; 0508 0509 return $this->_data['commentfeedlink']; 0510 } 0511 0512 /** 0513 * Get all categories 0514 * 0515 * @return Zend_Feed_Reader_Collection_Category 0516 */ 0517 public function getCategories() 0518 { 0519 if (array_key_exists('categories', $this->_data)) { 0520 return $this->_data['categories']; 0521 } 0522 0523 if ($this->_getAtomType() == Zend_Feed_Reader::TYPE_ATOM_10) { 0524 $list = $this->getXpath()->query($this->getXpathPrefix() . '//atom:category'); 0525 } else { 0526 /** 0527 * Since Atom 0.3 did not support categories, it would have used the 0528 * Dublin Core extension. However there is a small possibility Atom 0.3 0529 * may have been retrofittied to use Atom 1.0 instead. 0530 */ 0531 $this->getXpath()->registerNamespace('atom10', Zend_Feed_Reader::NAMESPACE_ATOM_10); 0532 $list = $this->getXpath()->query($this->getXpathPrefix() . '//atom10:category'); 0533 } 0534 0535 if ($list->length) { 0536 $categoryCollection = new Zend_Feed_Reader_Collection_Category; 0537 foreach ($list as $category) { 0538 $categoryCollection[] = array( 0539 'term' => $category->getAttribute('term'), 0540 'scheme' => $category->getAttribute('scheme'), 0541 'label' => $category->getAttribute('label') 0542 ); 0543 } 0544 } else { 0545 return new Zend_Feed_Reader_Collection_Category; 0546 } 0547 0548 $this->_data['categories'] = $categoryCollection; 0549 0550 return $this->_data['categories']; 0551 } 0552 0553 /** 0554 * Get source feed metadata from the entry 0555 * 0556 * @return Zend_Feed_Reader_Feed_Atom_Source|null 0557 */ 0558 public function getSource() 0559 { 0560 if (array_key_exists('source', $this->_data)) { 0561 return $this->_data['source']; 0562 } 0563 0564 $source = null; 0565 // TODO: Investigate why _getAtomType() fails here. Is it even needed? 0566 if ($this->getType() == Zend_Feed_Reader::TYPE_ATOM_10) { 0567 $list = $this->getXpath()->query($this->getXpathPrefix() . '/atom:source[1]'); 0568 if ($list->length) { 0569 $element = $list->item(0); 0570 $source = new Zend_Feed_Reader_Feed_Atom_Source($element, $this->getXpathPrefix()); 0571 } 0572 } 0573 0574 $this->_data['source'] = $source; 0575 return $this->_data['source']; 0576 } 0577 0578 /** 0579 * Attempt to absolutise the URI, i.e. if a relative URI apply the 0580 * xml:base value as a prefix to turn into an absolute URI. 0581 */ 0582 protected function _absolutiseUri($link) 0583 { 0584 if (!Zend_Uri::check($link)) { 0585 if ($this->getBaseUrl() !== null) { 0586 $link = $this->getBaseUrl() . $link; 0587 if (!Zend_Uri::check($link)) { 0588 $link = null; 0589 } 0590 } 0591 } 0592 return $link; 0593 } 0594 0595 /** 0596 * Get an author entry 0597 * 0598 * @param DOMElement $element 0599 * @return string 0600 */ 0601 protected function _getAuthor(DOMElement $element) 0602 { 0603 $author = array(); 0604 0605 $emailNode = $element->getElementsByTagName('email'); 0606 $nameNode = $element->getElementsByTagName('name'); 0607 $uriNode = $element->getElementsByTagName('uri'); 0608 0609 if ($emailNode->length && strlen($emailNode->item(0)->nodeValue) > 0) { 0610 $author['email'] = $emailNode->item(0)->nodeValue; 0611 } 0612 0613 if ($nameNode->length && strlen($nameNode->item(0)->nodeValue) > 0) { 0614 $author['name'] = $nameNode->item(0)->nodeValue; 0615 } 0616 0617 if ($uriNode->length && strlen($uriNode->item(0)->nodeValue) > 0) { 0618 $author['uri'] = $uriNode->item(0)->nodeValue; 0619 } 0620 0621 if (empty($author)) { 0622 return null; 0623 } 0624 return $author; 0625 } 0626 0627 /** 0628 * Register the default namespaces for the current feed format 0629 */ 0630 protected function _registerNamespaces() 0631 { 0632 switch ($this->_getAtomType()) { 0633 case Zend_Feed_Reader::TYPE_ATOM_03: 0634 $this->getXpath()->registerNamespace('atom', Zend_Feed_Reader::NAMESPACE_ATOM_03); 0635 break; 0636 default: 0637 $this->getXpath()->registerNamespace('atom', Zend_Feed_Reader::NAMESPACE_ATOM_10); 0638 break; 0639 } 0640 } 0641 0642 /** 0643 * Detect the presence of any Atom namespaces in use 0644 */ 0645 protected function _getAtomType() 0646 { 0647 $dom = $this->getDomDocument(); 0648 $prefixAtom03 = $dom->lookupPrefix(Zend_Feed_Reader::NAMESPACE_ATOM_03); 0649 $prefixAtom10 = $dom->lookupPrefix(Zend_Feed_Reader::NAMESPACE_ATOM_10); 0650 if ($dom->isDefaultNamespace(Zend_Feed_Reader::NAMESPACE_ATOM_03) 0651 || !empty($prefixAtom03)) { 0652 return Zend_Feed_Reader::TYPE_ATOM_03; 0653 } 0654 if ($dom->isDefaultNamespace(Zend_Feed_Reader::NAMESPACE_ATOM_10) 0655 || !empty($prefixAtom10)) { 0656 return Zend_Feed_Reader::TYPE_ATOM_10; 0657 } 0658 } 0659 }