Chris@0
|
1 <?php
|
Chris@0
|
2 /**
|
Chris@0
|
3 * Zend Framework (http://framework.zend.com/)
|
Chris@0
|
4 *
|
Chris@0
|
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
|
Chris@0
|
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
|
Chris@0
|
7 * @license http://framework.zend.com/license/new-bsd New BSD License
|
Chris@0
|
8 */
|
Chris@0
|
9
|
Chris@0
|
10 namespace Zend\Feed\Reader;
|
Chris@0
|
11
|
Chris@0
|
12 use ArrayObject;
|
Chris@0
|
13 use DOMNodeList;
|
Chris@0
|
14 use Zend\Feed\Uri;
|
Chris@0
|
15
|
Chris@0
|
16 class FeedSet extends ArrayObject
|
Chris@0
|
17 {
|
Chris@0
|
18 public $rss = null;
|
Chris@0
|
19
|
Chris@0
|
20 public $rdf = null;
|
Chris@0
|
21
|
Chris@0
|
22 public $atom = null;
|
Chris@0
|
23
|
Chris@0
|
24 /**
|
Chris@0
|
25 * Import a DOMNodeList from any document containing a set of links
|
Chris@0
|
26 * for alternate versions of a document, which will normally refer to
|
Chris@0
|
27 * RSS/RDF/Atom feeds for the current document.
|
Chris@0
|
28 *
|
Chris@0
|
29 * All such links are stored internally, however the first instance of
|
Chris@0
|
30 * each RSS, RDF or Atom type has its URI stored as a public property
|
Chris@0
|
31 * as a shortcut where the use case is simply to get a quick feed ref.
|
Chris@0
|
32 *
|
Chris@0
|
33 * Note that feeds are not loaded at this point, but will be lazy
|
Chris@0
|
34 * loaded automatically when each links 'feed' array key is accessed.
|
Chris@0
|
35 *
|
Chris@0
|
36 * @param DOMNodeList $links
|
Chris@0
|
37 * @param string $uri
|
Chris@0
|
38 * @return void
|
Chris@0
|
39 */
|
Chris@0
|
40 public function addLinks(DOMNodeList $links, $uri)
|
Chris@0
|
41 {
|
Chris@0
|
42 foreach ($links as $link) {
|
Chris@0
|
43 if (strtolower($link->getAttribute('rel')) !== 'alternate'
|
Chris@12
|
44 || ! $link->getAttribute('type') || ! $link->getAttribute('href')) {
|
Chris@0
|
45 continue;
|
Chris@0
|
46 }
|
Chris@12
|
47 if (! isset($this->rss) && $link->getAttribute('type') == 'application/rss+xml') {
|
Chris@0
|
48 $this->rss = $this->absolutiseUri(trim($link->getAttribute('href')), $uri);
|
Chris@12
|
49 } elseif (! isset($this->atom) && $link->getAttribute('type') == 'application/atom+xml') {
|
Chris@0
|
50 $this->atom = $this->absolutiseUri(trim($link->getAttribute('href')), $uri);
|
Chris@12
|
51 } elseif (! isset($this->rdf) && $link->getAttribute('type') == 'application/rdf+xml') {
|
Chris@0
|
52 $this->rdf = $this->absolutiseUri(trim($link->getAttribute('href')), $uri);
|
Chris@0
|
53 }
|
Chris@0
|
54 $this[] = new static([
|
Chris@0
|
55 'rel' => 'alternate',
|
Chris@0
|
56 'type' => $link->getAttribute('type'),
|
Chris@0
|
57 'href' => $this->absolutiseUri(trim($link->getAttribute('href')), $uri),
|
Chris@12
|
58 'title' => $link->getAttribute('title'),
|
Chris@0
|
59 ]);
|
Chris@0
|
60 }
|
Chris@0
|
61 }
|
Chris@0
|
62
|
Chris@0
|
63 /**
|
Chris@0
|
64 * Attempt to turn a relative URI into an absolute URI
|
Chris@12
|
65 *
|
Chris@12
|
66 * @param string $link
|
Chris@12
|
67 * @param string $uri OPTIONAL
|
Chris@12
|
68 * @return string|null absolutised link or null if invalid
|
Chris@0
|
69 */
|
Chris@0
|
70 protected function absolutiseUri($link, $uri = null)
|
Chris@0
|
71 {
|
Chris@0
|
72 $linkUri = Uri::factory($link);
|
Chris@12
|
73 if ($linkUri->isAbsolute()) {
|
Chris@12
|
74 // invalid absolute link can not be recovered
|
Chris@12
|
75 return $linkUri->isValid() ? $link : null;
|
Chris@12
|
76 }
|
Chris@0
|
77
|
Chris@12
|
78 $scheme = 'http';
|
Chris@12
|
79 if ($uri !== null) {
|
Chris@12
|
80 $uri = Uri::factory($uri);
|
Chris@12
|
81 $scheme = $uri->getScheme() ?: $scheme;
|
Chris@12
|
82 }
|
Chris@0
|
83
|
Chris@12
|
84 if ($linkUri->getHost()) {
|
Chris@12
|
85 $link = $this->resolveSchemeRelativeUri($link, $scheme);
|
Chris@12
|
86 } elseif ($uri !== null) {
|
Chris@12
|
87 $link = $this->resolveRelativeUri($link, $scheme, $uri->getHost(), $uri->getPath());
|
Chris@12
|
88 }
|
Chris@0
|
89
|
Chris@12
|
90 if (! Uri::factory($link)->isValid()) {
|
Chris@12
|
91 return null;
|
Chris@0
|
92 }
|
Chris@12
|
93
|
Chris@0
|
94 return $link;
|
Chris@0
|
95 }
|
Chris@0
|
96
|
Chris@0
|
97 /**
|
Chris@12
|
98 * Resolves scheme relative link to absolute
|
Chris@12
|
99 *
|
Chris@12
|
100 * @param string $link
|
Chris@12
|
101 * @param string $scheme
|
Chris@12
|
102 * @return string
|
Chris@12
|
103 */
|
Chris@12
|
104 private function resolveSchemeRelativeUri($link, $scheme)
|
Chris@12
|
105 {
|
Chris@12
|
106 $link = ltrim($link, '/');
|
Chris@12
|
107 return sprintf('%s://%s', $scheme, $link);
|
Chris@12
|
108 }
|
Chris@12
|
109
|
Chris@12
|
110 /**
|
Chris@12
|
111 * Resolves relative link to absolute
|
Chris@12
|
112 *
|
Chris@12
|
113 * @param string $link
|
Chris@12
|
114 * @param string $scheme
|
Chris@12
|
115 * @param string $host
|
Chris@12
|
116 * @param string $uriPath
|
Chris@12
|
117 * @return string
|
Chris@12
|
118 */
|
Chris@12
|
119 private function resolveRelativeUri($link, $scheme, $host, $uriPath)
|
Chris@12
|
120 {
|
Chris@12
|
121 if ($link[0] !== '/') {
|
Chris@12
|
122 $link = $uriPath . '/' . $link;
|
Chris@12
|
123 }
|
Chris@12
|
124 return sprintf(
|
Chris@12
|
125 '%s://%s/%s',
|
Chris@12
|
126 $scheme,
|
Chris@12
|
127 $host,
|
Chris@12
|
128 $this->canonicalizePath($link)
|
Chris@12
|
129 );
|
Chris@12
|
130 }
|
Chris@12
|
131
|
Chris@12
|
132 /**
|
Chris@0
|
133 * Canonicalize relative path
|
Chris@17
|
134 *
|
Chris@17
|
135 * @param string $path
|
Chris@17
|
136 * @return string
|
Chris@0
|
137 */
|
Chris@0
|
138 protected function canonicalizePath($path)
|
Chris@0
|
139 {
|
Chris@0
|
140 $parts = array_filter(explode('/', $path));
|
Chris@0
|
141 $absolutes = [];
|
Chris@0
|
142 foreach ($parts as $part) {
|
Chris@0
|
143 if ('.' == $part) {
|
Chris@0
|
144 continue;
|
Chris@0
|
145 }
|
Chris@0
|
146 if ('..' == $part) {
|
Chris@0
|
147 array_pop($absolutes);
|
Chris@0
|
148 } else {
|
Chris@0
|
149 $absolutes[] = $part;
|
Chris@0
|
150 }
|
Chris@0
|
151 }
|
Chris@0
|
152 return implode('/', $absolutes);
|
Chris@0
|
153 }
|
Chris@0
|
154
|
Chris@0
|
155 /**
|
Chris@0
|
156 * Supports lazy loading of feeds using Reader::import() but
|
Chris@0
|
157 * delegates any other operations to the parent class.
|
Chris@0
|
158 *
|
Chris@0
|
159 * @param string $offset
|
Chris@0
|
160 * @return mixed
|
Chris@0
|
161 */
|
Chris@0
|
162 public function offsetGet($offset)
|
Chris@0
|
163 {
|
Chris@12
|
164 if ($offset == 'feed' && ! $this->offsetExists('feed')) {
|
Chris@12
|
165 if (! $this->offsetExists('href')) {
|
Chris@0
|
166 return;
|
Chris@0
|
167 }
|
Chris@0
|
168 $feed = Reader::import($this->offsetGet('href'));
|
Chris@0
|
169 $this->offsetSet('feed', $feed);
|
Chris@0
|
170 return $feed;
|
Chris@0
|
171 }
|
Chris@0
|
172 return parent::offsetGet($offset);
|
Chris@0
|
173 }
|
Chris@0
|
174 }
|