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_Extension_FeedAbstract 0024 */ 0025 // require_once 'Zend/Feed/Reader/Extension/FeedAbstract.php'; 0026 0027 /** 0028 * @see Zend_Date 0029 */ 0030 // require_once 'Zend/Date.php'; 0031 0032 /** 0033 * @see Zend_Uri 0034 */ 0035 // require_once 'Zend/Uri.php'; 0036 0037 /** 0038 * @see Zend_Feed_Reader_Collection_Author 0039 */ 0040 // require_once 'Zend/Feed/Reader/Collection/Author.php'; 0041 0042 /** 0043 * @category Zend 0044 * @package Zend_Feed_Reader 0045 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0046 * @license http://framework.zend.com/license/new-bsd New BSD License 0047 */ 0048 class Zend_Feed_Reader_Extension_Atom_Feed 0049 extends Zend_Feed_Reader_Extension_FeedAbstract 0050 { 0051 /** 0052 * Get a single author 0053 * 0054 * @param int $index 0055 * @return string|null 0056 */ 0057 public function getAuthor($index = 0) 0058 { 0059 $authors = $this->getAuthors(); 0060 0061 if (isset($authors[$index])) { 0062 return $authors[$index]; 0063 } 0064 0065 return null; 0066 } 0067 0068 /** 0069 * Get an array with feed authors 0070 * 0071 * @return array 0072 */ 0073 public function getAuthors() 0074 { 0075 if (array_key_exists('authors', $this->_data)) { 0076 return $this->_data['authors']; 0077 } 0078 0079 $list = $this->_xpath->query('//atom:author'); 0080 0081 $authors = array(); 0082 0083 if ($list->length) { 0084 foreach ($list as $author) { 0085 $author = $this->_getAuthor($author); 0086 if (!empty($author)) { 0087 $authors[] = $author; 0088 } 0089 } 0090 } 0091 0092 if (count($authors) == 0) { 0093 $authors = null; 0094 } else { 0095 $authors = new Zend_Feed_Reader_Collection_Author( 0096 Zend_Feed_Reader::arrayUnique($authors) 0097 ); 0098 } 0099 0100 $this->_data['authors'] = $authors; 0101 0102 return $this->_data['authors']; 0103 } 0104 0105 /** 0106 * Get the copyright entry 0107 * 0108 * @return string|null 0109 */ 0110 public function getCopyright() 0111 { 0112 if (array_key_exists('copyright', $this->_data)) { 0113 return $this->_data['copyright']; 0114 } 0115 0116 $copyright = null; 0117 0118 if ($this->getType() === Zend_Feed_Reader::TYPE_ATOM_03) { 0119 $copyright = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:copyright)'); 0120 } else { 0121 $copyright = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:rights)'); 0122 } 0123 0124 if (!$copyright) { 0125 $copyright = null; 0126 } 0127 0128 $this->_data['copyright'] = $copyright; 0129 0130 return $this->_data['copyright']; 0131 } 0132 0133 /** 0134 * Get the feed creation date 0135 * 0136 * @return Zend_Date|null 0137 */ 0138 public function getDateCreated() 0139 { 0140 if (array_key_exists('datecreated', $this->_data)) { 0141 return $this->_data['datecreated']; 0142 } 0143 0144 $date = null; 0145 0146 if ($this->getType() === Zend_Feed_Reader::TYPE_ATOM_03) { 0147 $dateCreated = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:created)'); 0148 } else { 0149 $dateCreated = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:published)'); 0150 } 0151 0152 if ($dateCreated) { 0153 $date = new Zend_Date; 0154 $date->set($dateCreated, Zend_Date::ISO_8601); 0155 } 0156 0157 $this->_data['datecreated'] = $date; 0158 0159 return $this->_data['datecreated']; 0160 } 0161 0162 /** 0163 * Get the feed modification date 0164 * 0165 * @return Zend_Date|null 0166 */ 0167 public function getDateModified() 0168 { 0169 if (array_key_exists('datemodified', $this->_data)) { 0170 return $this->_data['datemodified']; 0171 } 0172 0173 $date = null; 0174 0175 if ($this->getType() === Zend_Feed_Reader::TYPE_ATOM_03) { 0176 $dateModified = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:modified)'); 0177 } else { 0178 $dateModified = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:updated)'); 0179 } 0180 0181 if ($dateModified) { 0182 $date = new Zend_Date; 0183 $date->set($dateModified, Zend_Date::ISO_8601); 0184 } 0185 0186 $this->_data['datemodified'] = $date; 0187 0188 return $this->_data['datemodified']; 0189 } 0190 0191 /** 0192 * Get the feed description 0193 * 0194 * @return string|null 0195 */ 0196 public function getDescription() 0197 { 0198 if (array_key_exists('description', $this->_data)) { 0199 return $this->_data['description']; 0200 } 0201 0202 $description = null; 0203 0204 if ($this->getType() === Zend_Feed_Reader::TYPE_ATOM_03) { 0205 $description = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:tagline)'); // TODO: Is this the same as subtitle? 0206 } else { 0207 $description = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:subtitle)'); 0208 } 0209 0210 if (!$description) { 0211 $description = null; 0212 } 0213 0214 $this->_data['description'] = $description; 0215 0216 return $this->_data['description']; 0217 } 0218 0219 /** 0220 * Get the feed generator entry 0221 * 0222 * @return string|null 0223 */ 0224 public function getGenerator() 0225 { 0226 if (array_key_exists('generator', $this->_data)) { 0227 return $this->_data['generator']; 0228 } 0229 // TODO: Add uri support 0230 $generator = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:generator)'); 0231 0232 if (!$generator) { 0233 $generator = null; 0234 } 0235 0236 $this->_data['generator'] = $generator; 0237 0238 return $this->_data['generator']; 0239 } 0240 0241 /** 0242 * Get the feed ID 0243 * 0244 * @return string|null 0245 */ 0246 public function getId() 0247 { 0248 if (array_key_exists('id', $this->_data)) { 0249 return $this->_data['id']; 0250 } 0251 0252 $id = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:id)'); 0253 0254 if (!$id) { 0255 if ($this->getLink()) { 0256 $id = $this->getLink(); 0257 } elseif ($this->getTitle()) { 0258 $id = $this->getTitle(); 0259 } else { 0260 $id = null; 0261 } 0262 } 0263 0264 $this->_data['id'] = $id; 0265 0266 return $this->_data['id']; 0267 } 0268 0269 /** 0270 * Get the feed language 0271 * 0272 * @return string|null 0273 */ 0274 public function getLanguage() 0275 { 0276 if (array_key_exists('language', $this->_data)) { 0277 return $this->_data['language']; 0278 } 0279 0280 $language = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:lang)'); 0281 0282 if (!$language) { 0283 $language = $this->_xpath->evaluate('string(//@xml:lang[1])'); 0284 } 0285 0286 if (!$language) { 0287 $language = null; 0288 } 0289 0290 $this->_data['language'] = $language; 0291 0292 return $this->_data['language']; 0293 } 0294 0295 /** 0296 * Get the feed image 0297 * 0298 * @return array|null 0299 */ 0300 public function getImage() 0301 { 0302 if (array_key_exists('image', $this->_data)) { 0303 return $this->_data['image']; 0304 } 0305 0306 $imageUrl = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:logo)'); 0307 0308 if (!$imageUrl) { 0309 $image = null; 0310 } else { 0311 $image = array('uri'=>$imageUrl); 0312 } 0313 0314 $this->_data['image'] = $image; 0315 0316 return $this->_data['image']; 0317 } 0318 0319 /** 0320 * Get the feed image 0321 * 0322 * @return array|null 0323 */ 0324 public function getIcon() 0325 { 0326 if (array_key_exists('icon', $this->_data)) { 0327 return $this->_data['icon']; 0328 } 0329 0330 $imageUrl = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:icon)'); 0331 0332 if (!$imageUrl) { 0333 $image = null; 0334 } else { 0335 $image = array('uri'=>$imageUrl); 0336 } 0337 0338 $this->_data['icon'] = $image; 0339 0340 return $this->_data['icon']; 0341 } 0342 0343 /** 0344 * Get the base URI of the feed (if set). 0345 * 0346 * @return string|null 0347 */ 0348 public function getBaseUrl() 0349 { 0350 if (array_key_exists('baseUrl', $this->_data)) { 0351 return $this->_data['baseUrl']; 0352 } 0353 0354 $baseUrl = $this->_xpath->evaluate('string(//@xml:base[1])'); 0355 0356 if (!$baseUrl) { 0357 $baseUrl = null; 0358 } 0359 $this->_data['baseUrl'] = $baseUrl; 0360 0361 return $this->_data['baseUrl']; 0362 } 0363 0364 /** 0365 * Get a link to the source website 0366 * 0367 * @return string|null 0368 */ 0369 public function getLink() 0370 { 0371 if (array_key_exists('link', $this->_data)) { 0372 return $this->_data['link']; 0373 } 0374 0375 $link = null; 0376 0377 $list = $this->_xpath->query( 0378 $this->getXpathPrefix() . '/atom:link[@rel="alternate"]/@href' . '|' . 0379 $this->getXpathPrefix() . '/atom:link[not(@rel)]/@href' 0380 ); 0381 0382 if ($list->length) { 0383 $link = $list->item(0)->nodeValue; 0384 $link = $this->_absolutiseUri($link); 0385 } 0386 0387 $this->_data['link'] = $link; 0388 0389 return $this->_data['link']; 0390 } 0391 0392 /** 0393 * Get a link to the feed's XML Url 0394 * 0395 * @return string|null 0396 */ 0397 public function getFeedLink() 0398 { 0399 if (array_key_exists('feedlink', $this->_data)) { 0400 return $this->_data['feedlink']; 0401 } 0402 0403 $link = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:link[@rel="self"]/@href)'); 0404 0405 $link = $this->_absolutiseUri($link); 0406 0407 $this->_data['feedlink'] = $link; 0408 0409 return $this->_data['feedlink']; 0410 } 0411 0412 /** 0413 * Get an array of any supported Pusubhubbub endpoints 0414 * 0415 * @return array|null 0416 */ 0417 public function getHubs() 0418 { 0419 if (array_key_exists('hubs', $this->_data)) { 0420 return $this->_data['hubs']; 0421 } 0422 $hubs = array(); 0423 0424 $list = $this->_xpath->query($this->getXpathPrefix() 0425 . '//atom:link[@rel="hub"]/@href'); 0426 0427 if ($list->length) { 0428 foreach ($list as $uri) { 0429 $hubs[] = $this->_absolutiseUri($uri->nodeValue); 0430 } 0431 } else { 0432 $hubs = null; 0433 } 0434 0435 $this->_data['hubs'] = $hubs; 0436 0437 return $this->_data['hubs']; 0438 } 0439 0440 /** 0441 * Get the feed title 0442 * 0443 * @return string|null 0444 */ 0445 public function getTitle() 0446 { 0447 if (array_key_exists('title', $this->_data)) { 0448 return $this->_data['title']; 0449 } 0450 0451 $title = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:title)'); 0452 0453 if (!$title) { 0454 $title = null; 0455 } 0456 0457 $this->_data['title'] = $title; 0458 0459 return $this->_data['title']; 0460 } 0461 0462 /** 0463 * Get all categories 0464 * 0465 * @return Zend_Feed_Reader_Collection_Category 0466 */ 0467 public function getCategories() 0468 { 0469 if (array_key_exists('categories', $this->_data)) { 0470 return $this->_data['categories']; 0471 } 0472 0473 if ($this->getType() == Zend_Feed_Reader::TYPE_ATOM_10) { 0474 $list = $this->_xpath->query($this->getXpathPrefix() . '/atom:category'); 0475 } else { 0476 /** 0477 * Since Atom 0.3 did not support categories, it would have used the 0478 * Dublin Core extension. However there is a small possibility Atom 0.3 0479 * may have been retrofittied to use Atom 1.0 instead. 0480 */ 0481 $this->_xpath->registerNamespace('atom10', Zend_Feed_Reader::NAMESPACE_ATOM_10); 0482 $list = $this->_xpath->query($this->getXpathPrefix() . '/atom10:category'); 0483 } 0484 0485 if ($list->length) { 0486 $categoryCollection = new Zend_Feed_Reader_Collection_Category; 0487 foreach ($list as $category) { 0488 $categoryCollection[] = array( 0489 'term' => $category->getAttribute('term'), 0490 'scheme' => $category->getAttribute('scheme'), 0491 'label' => $category->getAttribute('label') 0492 ); 0493 } 0494 } else { 0495 return new Zend_Feed_Reader_Collection_Category; 0496 } 0497 0498 $this->_data['categories'] = $categoryCollection; 0499 0500 return $this->_data['categories']; 0501 } 0502 0503 /** 0504 * Get an author entry in RSS format 0505 * 0506 * @param DOMElement $element 0507 * @return string 0508 */ 0509 protected function _getAuthor(DOMElement $element) 0510 { 0511 $author = array(); 0512 0513 $emailNode = $element->getElementsByTagName('email'); 0514 $nameNode = $element->getElementsByTagName('name'); 0515 $uriNode = $element->getElementsByTagName('uri'); 0516 0517 if ($emailNode->length && strlen($emailNode->item(0)->nodeValue) > 0) { 0518 $author['email'] = $emailNode->item(0)->nodeValue; 0519 } 0520 0521 if ($nameNode->length && strlen($nameNode->item(0)->nodeValue) > 0) { 0522 $author['name'] = $nameNode->item(0)->nodeValue; 0523 } 0524 0525 if ($uriNode->length && strlen($uriNode->item(0)->nodeValue) > 0) { 0526 $author['uri'] = $uriNode->item(0)->nodeValue; 0527 } 0528 0529 if (empty($author)) { 0530 return null; 0531 } 0532 return $author; 0533 } 0534 0535 /** 0536 * Attempt to absolutise the URI, i.e. if a relative URI apply the 0537 * xml:base value as a prefix to turn into an absolute URI. 0538 */ 0539 protected function _absolutiseUri($link) 0540 { 0541 if (!Zend_Uri::check($link)) { 0542 if ($this->getBaseUrl() !== null) { 0543 $link = $this->getBaseUrl() . $link; 0544 if (!Zend_Uri::check($link)) { 0545 $link = null; 0546 } 0547 } 0548 } 0549 return $link; 0550 } 0551 0552 /** 0553 * Register the default namespaces for the current feed format 0554 */ 0555 protected function _registerNamespaces() 0556 { 0557 if ($this->getType() == Zend_Feed_Reader::TYPE_ATOM_10 0558 || $this->getType() == Zend_Feed_Reader::TYPE_ATOM_03 0559 ) { 0560 return; // pre-registered at Feed level 0561 } 0562 $atomDetected = $this->_getAtomType(); 0563 switch ($atomDetected) { 0564 case Zend_Feed_Reader::TYPE_ATOM_03: 0565 $this->_xpath->registerNamespace('atom', Zend_Feed_Reader::NAMESPACE_ATOM_03); 0566 break; 0567 default: 0568 $this->_xpath->registerNamespace('atom', Zend_Feed_Reader::NAMESPACE_ATOM_10); 0569 break; 0570 } 0571 } 0572 0573 /** 0574 * Detect the presence of any Atom namespaces in use 0575 */ 0576 protected function _getAtomType() 0577 { 0578 $dom = $this->getDomDocument(); 0579 $prefixAtom03 = $dom->lookupPrefix(Zend_Feed_Reader::NAMESPACE_ATOM_03); 0580 $prefixAtom10 = $dom->lookupPrefix(Zend_Feed_Reader::NAMESPACE_ATOM_10); 0581 if ($dom->isDefaultNamespace(Zend_Feed_Reader::NAMESPACE_ATOM_10) 0582 || !empty($prefixAtom10)) { 0583 return Zend_Feed_Reader::TYPE_ATOM_10; 0584 } 0585 if ($dom->isDefaultNamespace(Zend_Feed_Reader::NAMESPACE_ATOM_03) 0586 || !empty($prefixAtom03)) { 0587 return Zend_Feed_Reader::TYPE_ATOM_03; 0588 } 0589 } 0590 }