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 }