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 }