db backup prior to drupal security update
[yaffs-website] / vendor / zendframework / zend-feed / src / Reader / Entry / Rss.php
1 <?php
2 /**
3  * Zend Framework (http://framework.zend.com/)
4  *
5  * @link      http://github.com/zendframework/zf2 for the canonical source repository
6  * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7  * @license   http://framework.zend.com/license/new-bsd New BSD License
8  */
9
10 namespace Zend\Feed\Reader\Entry;
11
12 use DateTime;
13 use DOMElement;
14 use DOMXPath;
15 use Zend\Feed\Reader;
16 use Zend\Feed\Reader\Exception;
17
18 class Rss extends AbstractEntry implements EntryInterface
19 {
20     /**
21      * XPath query for RDF
22      *
23      * @var string
24      */
25     protected $xpathQueryRdf = '';
26
27     /**
28      * XPath query for RSS
29      *
30      * @var string
31      */
32     protected $xpathQueryRss = '';
33
34     /**
35      * Constructor
36      *
37      * @param  DOMElement $entry
38      * @param  string $entryKey
39      * @param  string $type
40      */
41     public function __construct(DOMElement $entry, $entryKey, $type = null)
42     {
43         parent::__construct($entry, $entryKey, $type);
44         $this->xpathQueryRss = '//item[' . ($this->entryKey + 1) . ']';
45         $this->xpathQueryRdf = '//rss:item[' . ($this->entryKey + 1) . ']';
46
47         $manager    = Reader\Reader::getExtensionManager();
48         $extensions = [
49             'DublinCore\Entry',
50             'Content\Entry',
51             'Atom\Entry',
52             'WellFormedWeb\Entry',
53             'Slash\Entry',
54             'Thread\Entry',
55         ];
56         foreach ($extensions as $name) {
57             $extension = $manager->get($name);
58             $extension->setEntryElement($entry);
59             $extension->setEntryKey($entryKey);
60             $extension->setType($type);
61             $this->extensions[$name] = $extension;
62         }
63     }
64
65     /**
66      * Get an author entry
67      *
68      * @param int $index
69      * @return string
70      */
71     public function getAuthor($index = 0)
72     {
73         $authors = $this->getAuthors();
74
75         if (isset($authors[$index])) {
76             return $authors[$index];
77         }
78
79         return;
80     }
81
82     /**
83      * Get an array with feed authors
84      *
85      * @return array
86      */
87     public function getAuthors()
88     {
89         if (array_key_exists('authors', $this->data)) {
90             return $this->data['authors'];
91         }
92
93         $authors = [];
94         $authorsDc = $this->getExtension('DublinCore')->getAuthors();
95         if (! empty($authorsDc)) {
96             foreach ($authorsDc as $author) {
97                 $authors[] = [
98                     'name' => $author['name']
99                 ];
100             }
101         }
102
103         if ($this->getType() !== Reader\Reader::TYPE_RSS_10
104         && $this->getType() !== Reader\Reader::TYPE_RSS_090) {
105             $list = $this->xpath->query($this->xpathQueryRss . '//author');
106         } else {
107             $list = $this->xpath->query($this->xpathQueryRdf . '//rss:author');
108         }
109         if ($list->length) {
110             foreach ($list as $author) {
111                 $string = trim($author->nodeValue);
112                 $data = [];
113                 // Pretty rough parsing - but it's a catchall
114                 if (preg_match("/^.*@[^ ]*/", $string, $matches)) {
115                     $data['email'] = trim($matches[0]);
116                     if (preg_match("/\((.*)\)$/", $string, $matches)) {
117                         $data['name'] = $matches[1];
118                     }
119                     $authors[] = $data;
120                 }
121             }
122         }
123
124         if (count($authors) == 0) {
125             $authors = $this->getExtension('Atom')->getAuthors();
126         } else {
127             $authors = new Reader\Collection\Author(
128                 Reader\Reader::arrayUnique($authors)
129             );
130         }
131
132         if (count($authors) == 0) {
133             $authors = null;
134         }
135
136         $this->data['authors'] = $authors;
137
138         return $this->data['authors'];
139     }
140
141     /**
142      * Get the entry content
143      *
144      * @return string
145      */
146     public function getContent()
147     {
148         if (array_key_exists('content', $this->data)) {
149             return $this->data['content'];
150         }
151
152         $content = $this->getExtension('Content')->getContent();
153
154         if (! $content) {
155             $content = $this->getDescription();
156         }
157
158         if (empty($content)) {
159             $content = $this->getExtension('Atom')->getContent();
160         }
161
162         $this->data['content'] = $content;
163
164         return $this->data['content'];
165     }
166
167     /**
168      * Get the entry's date of creation
169      *
170      * @return \DateTime
171      */
172     public function getDateCreated()
173     {
174         return $this->getDateModified();
175     }
176
177     /**
178      * Get the entry's date of modification
179      *
180      * @throws Exception\RuntimeException
181      * @return \DateTime
182      */
183     public function getDateModified()
184     {
185         if (array_key_exists('datemodified', $this->data)) {
186             return $this->data['datemodified'];
187         }
188
189         $date = null;
190
191         if ($this->getType() !== Reader\Reader::TYPE_RSS_10
192             && $this->getType() !== Reader\Reader::TYPE_RSS_090
193         ) {
194             $dateModified = $this->xpath->evaluate('string(' . $this->xpathQueryRss . '/pubDate)');
195             if ($dateModified) {
196                 $dateModifiedParsed = strtotime($dateModified);
197                 if ($dateModifiedParsed) {
198                     $date = new DateTime('@' . $dateModifiedParsed);
199                 } else {
200                     $dateStandards = [DateTime::RSS, DateTime::RFC822,
201                                            DateTime::RFC2822, null];
202                     foreach ($dateStandards as $standard) {
203                         try {
204                             $date = date_create_from_format($standard, $dateModified);
205                             break;
206                         } catch (\Exception $e) {
207                             if ($standard === null) {
208                                 throw new Exception\RuntimeException(
209                                     'Could not load date due to unrecognised'
210                                     .' format (should follow RFC 822 or 2822):'
211                                     . $e->getMessage(),
212                                     0,
213                                     $e
214                                 );
215                             }
216                         }
217                     }
218                 }
219             }
220         }
221
222         if (! $date) {
223             $date = $this->getExtension('DublinCore')->getDate();
224         }
225
226         if (! $date) {
227             $date = $this->getExtension('Atom')->getDateModified();
228         }
229
230         if (! $date) {
231             $date = null;
232         }
233
234         $this->data['datemodified'] = $date;
235
236         return $this->data['datemodified'];
237     }
238
239     /**
240      * Get the entry description
241      *
242      * @return string
243      */
244     public function getDescription()
245     {
246         if (array_key_exists('description', $this->data)) {
247             return $this->data['description'];
248         }
249
250         $description = null;
251
252         if ($this->getType() !== Reader\Reader::TYPE_RSS_10
253             && $this->getType() !== Reader\Reader::TYPE_RSS_090
254         ) {
255             $description = $this->xpath->evaluate('string(' . $this->xpathQueryRss . '/description)');
256         } else {
257             $description = $this->xpath->evaluate('string(' . $this->xpathQueryRdf . '/rss:description)');
258         }
259
260         if (! $description) {
261             $description = $this->getExtension('DublinCore')->getDescription();
262         }
263
264         if (empty($description)) {
265             $description = $this->getExtension('Atom')->getDescription();
266         }
267
268         if (! $description) {
269             $description = null;
270         }
271
272         $this->data['description'] = $description;
273
274         return $this->data['description'];
275     }
276
277     /**
278      * Get the entry enclosure
279      * @return string
280      */
281     public function getEnclosure()
282     {
283         if (array_key_exists('enclosure', $this->data)) {
284             return $this->data['enclosure'];
285         }
286
287         $enclosure = null;
288
289         if ($this->getType() == Reader\Reader::TYPE_RSS_20) {
290             $nodeList = $this->xpath->query($this->xpathQueryRss . '/enclosure');
291
292             if ($nodeList->length > 0) {
293                 $enclosure = new \stdClass();
294                 $enclosure->url    = $nodeList->item(0)->getAttribute('url');
295                 $enclosure->length = $nodeList->item(0)->getAttribute('length');
296                 $enclosure->type   = $nodeList->item(0)->getAttribute('type');
297             }
298         }
299
300         if (! $enclosure) {
301             $enclosure = $this->getExtension('Atom')->getEnclosure();
302         }
303
304         $this->data['enclosure'] = $enclosure;
305
306         return $this->data['enclosure'];
307     }
308
309     /**
310      * Get the entry ID
311      *
312      * @return string
313      */
314     public function getId()
315     {
316         if (array_key_exists('id', $this->data)) {
317             return $this->data['id'];
318         }
319
320         $id = null;
321
322         if ($this->getType() !== Reader\Reader::TYPE_RSS_10
323             && $this->getType() !== Reader\Reader::TYPE_RSS_090
324         ) {
325             $id = $this->xpath->evaluate('string(' . $this->xpathQueryRss . '/guid)');
326         }
327
328         if (! $id) {
329             $id = $this->getExtension('DublinCore')->getId();
330         }
331
332         if (empty($id)) {
333             $id = $this->getExtension('Atom')->getId();
334         }
335
336         if (! $id) {
337             if ($this->getPermalink()) {
338                 $id = $this->getPermalink();
339             } elseif ($this->getTitle()) {
340                 $id = $this->getTitle();
341             } else {
342                 $id = null;
343             }
344         }
345
346         $this->data['id'] = $id;
347
348         return $this->data['id'];
349     }
350
351     /**
352      * Get a specific link
353      *
354      * @param  int $index
355      * @return string
356      */
357     public function getLink($index = 0)
358     {
359         if (! array_key_exists('links', $this->data)) {
360             $this->getLinks();
361         }
362
363         if (isset($this->data['links'][$index])) {
364             return $this->data['links'][$index];
365         }
366
367         return;
368     }
369
370     /**
371      * Get all links
372      *
373      * @return array
374      */
375     public function getLinks()
376     {
377         if (array_key_exists('links', $this->data)) {
378             return $this->data['links'];
379         }
380
381         $links = [];
382
383         if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
384             $this->getType() !== Reader\Reader::TYPE_RSS_090) {
385             $list = $this->xpath->query($this->xpathQueryRss . '//link');
386         } else {
387             $list = $this->xpath->query($this->xpathQueryRdf . '//rss:link');
388         }
389
390         if (! $list->length) {
391             $links = $this->getExtension('Atom')->getLinks();
392         } else {
393             foreach ($list as $link) {
394                 $links[] = $link->nodeValue;
395             }
396         }
397
398         $this->data['links'] = $links;
399
400         return $this->data['links'];
401     }
402
403     /**
404      * Get all categories
405      *
406      * @return Reader\Collection\Category
407      */
408     public function getCategories()
409     {
410         if (array_key_exists('categories', $this->data)) {
411             return $this->data['categories'];
412         }
413
414         if ($this->getType() !== Reader\Reader::TYPE_RSS_10 &&
415             $this->getType() !== Reader\Reader::TYPE_RSS_090) {
416             $list = $this->xpath->query($this->xpathQueryRss . '//category');
417         } else {
418             $list = $this->xpath->query($this->xpathQueryRdf . '//rss:category');
419         }
420
421         if ($list->length) {
422             $categoryCollection = new Reader\Collection\Category;
423             foreach ($list as $category) {
424                 $categoryCollection[] = [
425                     'term' => $category->nodeValue,
426                     'scheme' => $category->getAttribute('domain'),
427                     'label' => $category->nodeValue,
428                 ];
429             }
430         } else {
431             $categoryCollection = $this->getExtension('DublinCore')->getCategories();
432         }
433
434         if (count($categoryCollection) == 0) {
435             $categoryCollection = $this->getExtension('Atom')->getCategories();
436         }
437
438         $this->data['categories'] = $categoryCollection;
439
440         return $this->data['categories'];
441     }
442
443     /**
444      * Get a permalink to the entry
445      *
446      * @return string
447      */
448     public function getPermalink()
449     {
450         return $this->getLink(0);
451     }
452
453     /**
454      * Get the entry title
455      *
456      * @return string
457      */
458     public function getTitle()
459     {
460         if (array_key_exists('title', $this->data)) {
461             return $this->data['title'];
462         }
463
464         $title = null;
465
466         if ($this->getType() !== Reader\Reader::TYPE_RSS_10
467             && $this->getType() !== Reader\Reader::TYPE_RSS_090
468         ) {
469             $title = $this->xpath->evaluate('string(' . $this->xpathQueryRss . '/title)');
470         } else {
471             $title = $this->xpath->evaluate('string(' . $this->xpathQueryRdf . '/rss:title)');
472         }
473
474         if (! $title) {
475             $title = $this->getExtension('DublinCore')->getTitle();
476         }
477
478         if (! $title) {
479             $title = $this->getExtension('Atom')->getTitle();
480         }
481
482         if (! $title) {
483             $title = null;
484         }
485
486         $this->data['title'] = $title;
487
488         return $this->data['title'];
489     }
490
491     /**
492      * Get the number of comments/replies for current entry
493      *
494      * @return string|null
495      */
496     public function getCommentCount()
497     {
498         if (array_key_exists('commentcount', $this->data)) {
499             return $this->data['commentcount'];
500         }
501
502         $commentcount = $this->getExtension('Slash')->getCommentCount();
503
504         if (! $commentcount) {
505             $commentcount = $this->getExtension('Thread')->getCommentCount();
506         }
507
508         if (! $commentcount) {
509             $commentcount = $this->getExtension('Atom')->getCommentCount();
510         }
511
512         if (! $commentcount) {
513             $commentcount = null;
514         }
515
516         $this->data['commentcount'] = $commentcount;
517
518         return $this->data['commentcount'];
519     }
520
521     /**
522      * Returns a URI pointing to the HTML page where comments can be made on this entry
523      *
524      * @return string
525      */
526     public function getCommentLink()
527     {
528         if (array_key_exists('commentlink', $this->data)) {
529             return $this->data['commentlink'];
530         }
531
532         $commentlink = null;
533
534         if ($this->getType() !== Reader\Reader::TYPE_RSS_10
535             && $this->getType() !== Reader\Reader::TYPE_RSS_090
536         ) {
537             $commentlink = $this->xpath->evaluate('string(' . $this->xpathQueryRss . '/comments)');
538         }
539
540         if (! $commentlink) {
541             $commentlink = $this->getExtension('Atom')->getCommentLink();
542         }
543
544         if (! $commentlink) {
545             $commentlink = null;
546         }
547
548         $this->data['commentlink'] = $commentlink;
549
550         return $this->data['commentlink'];
551     }
552
553     /**
554      * Returns a URI pointing to a feed of all comments for this entry
555      *
556      * @return string
557      */
558     public function getCommentFeedLink()
559     {
560         if (array_key_exists('commentfeedlink', $this->data)) {
561             return $this->data['commentfeedlink'];
562         }
563
564         $commentfeedlink = $this->getExtension('WellFormedWeb')->getCommentFeedLink();
565
566         if (! $commentfeedlink) {
567             $commentfeedlink = $this->getExtension('Atom')->getCommentFeedLink('rss');
568         }
569
570         if (! $commentfeedlink) {
571             $commentfeedlink = $this->getExtension('Atom')->getCommentFeedLink('rdf');
572         }
573
574         if (! $commentfeedlink) {
575             $commentfeedlink = null;
576         }
577
578         $this->data['commentfeedlink'] = $commentfeedlink;
579
580         return $this->data['commentfeedlink'];
581     }
582
583     /**
584      * Set the XPath query (incl. on all Extensions)
585      *
586      * @param DOMXPath $xpath
587      * @return void
588      */
589     public function setXpath(DOMXPath $xpath)
590     {
591         parent::setXpath($xpath);
592         foreach ($this->extensions as $extension) {
593             $extension->setXpath($this->xpath);
594         }
595     }
596 }