]>
Commit | Line | Data |
---|---|---|
ec397236 NL |
1 | <?php |
2 | /** | |
3 | * SimplePie | |
4 | * | |
5 | * A PHP-Based RSS and Atom Feed Framework. | |
6 | * Takes the hard work out of managing a complete RSS/Atom solution. | |
7 | * | |
8 | * Copyright (c) 2004-2009, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors | |
9 | * All rights reserved. | |
10 | * | |
11 | * Redistribution and use in source and binary forms, with or without modification, are | |
12 | * permitted provided that the following conditions are met: | |
13 | * | |
14 | * * Redistributions of source code must retain the above copyright notice, this list of | |
15 | * conditions and the following disclaimer. | |
16 | * | |
17 | * * Redistributions in binary form must reproduce the above copyright notice, this list | |
18 | * of conditions and the following disclaimer in the documentation and/or other materials | |
19 | * provided with the distribution. | |
20 | * | |
21 | * * Neither the name of the SimplePie Team nor the names of its contributors may be used | |
22 | * to endorse or promote products derived from this software without specific prior | |
23 | * written permission. | |
24 | * | |
25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS | |
26 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
27 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS | |
28 | * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
31 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
32 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
33 | * POSSIBILITY OF SUCH DAMAGE. | |
34 | * | |
35 | * @package SimplePie | |
36 | * @version 1.3-dev | |
37 | * @copyright 2004-2010 Ryan Parman, Geoffrey Sneddon, Ryan McCue | |
38 | * @author Ryan Parman | |
39 | * @author Geoffrey Sneddon | |
40 | * @author Ryan McCue | |
41 | * @link http://simplepie.org/ SimplePie | |
42 | * @license http://www.opensource.org/licenses/bsd-license.php BSD License | |
43 | * @todo phpDoc comments | |
44 | */ | |
45 | ||
46 | ||
47 | class SimplePie_Locator | |
48 | { | |
49 | var $useragent; | |
50 | var $timeout; | |
51 | var $file; | |
52 | var $local = array(); | |
53 | var $elsewhere = array(); | |
54 | var $file_class = 'SimplePie_File'; | |
55 | var $cached_entities = array(); | |
56 | var $http_base; | |
57 | var $base; | |
58 | var $base_location = 0; | |
59 | var $checked_feeds = 0; | |
60 | var $max_checked_feeds = 10; | |
61 | var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer'; | |
62 | ||
63 | public function __construct(&$file, $timeout = 10, $useragent = null, $file_class = 'SimplePie_File', $max_checked_feeds = 10, $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer') | |
64 | { | |
65 | $this->file =& $file; | |
66 | $this->file_class = $file_class; | |
67 | $this->useragent = $useragent; | |
68 | $this->timeout = $timeout; | |
69 | $this->max_checked_feeds = $max_checked_feeds; | |
70 | $this->content_type_sniffer_class = $content_type_sniffer_class; | |
71 | } | |
72 | ||
73 | public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working) | |
74 | { | |
75 | if ($this->is_feed($this->file)) | |
76 | { | |
77 | return $this->file; | |
78 | } | |
79 | ||
80 | if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) | |
81 | { | |
82 | $sniffer = new $this->content_type_sniffer_class($this->file); | |
83 | if ($sniffer->get_type() !== 'text/html') | |
84 | { | |
85 | return null; | |
86 | } | |
87 | } | |
88 | ||
89 | if ($type & ~SIMPLEPIE_LOCATOR_NONE) | |
90 | { | |
91 | $this->get_base(); | |
92 | } | |
93 | ||
94 | if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery()) | |
95 | { | |
96 | return $working[0]; | |
97 | } | |
98 | ||
99 | if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links()) | |
100 | { | |
101 | if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local)) | |
102 | { | |
103 | return $working; | |
104 | } | |
105 | ||
106 | if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local)) | |
107 | { | |
108 | return $working; | |
109 | } | |
110 | ||
111 | if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere)) | |
112 | { | |
113 | return $working; | |
114 | } | |
115 | ||
116 | if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere)) | |
117 | { | |
118 | return $working; | |
119 | } | |
120 | } | |
121 | return null; | |
122 | } | |
123 | ||
124 | public function is_feed(&$file) | |
125 | { | |
126 | if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) | |
127 | { | |
128 | $sniffer = new $this->content_type_sniffer_class($file); | |
129 | $sniffed = $sniffer->get_type(); | |
130 | if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml'))) | |
131 | { | |
132 | return true; | |
133 | } | |
134 | else | |
135 | { | |
136 | return false; | |
137 | } | |
138 | } | |
139 | elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL) | |
140 | { | |
141 | return true; | |
142 | } | |
143 | else | |
144 | { | |
145 | return false; | |
146 | } | |
147 | } | |
148 | ||
149 | public function get_base() | |
150 | { | |
151 | $this->http_base = $this->file->url; | |
152 | $this->base = $this->http_base; | |
153 | $elements = SimplePie_Misc::get_element('base', $this->file->body); | |
154 | foreach ($elements as $element) | |
155 | { | |
156 | if ($element['attribs']['href']['data'] !== '') | |
157 | { | |
158 | $this->base = SimplePie_Misc::absolutize_url(trim($element['attribs']['href']['data']), $this->http_base); | |
159 | $this->base_location = $element['offset']; | |
160 | break; | |
161 | } | |
162 | } | |
163 | } | |
164 | ||
165 | public function autodiscovery() | |
166 | { | |
167 | $links = array_merge(SimplePie_Misc::get_element('link', $this->file->body), SimplePie_Misc::get_element('a', $this->file->body), SimplePie_Misc::get_element('area', $this->file->body)); | |
168 | $done = array(); | |
169 | $feeds = array(); | |
170 | foreach ($links as $link) | |
171 | { | |
172 | if ($this->checked_feeds === $this->max_checked_feeds) | |
173 | { | |
174 | break; | |
175 | } | |
176 | if (isset($link['attribs']['href']['data']) && isset($link['attribs']['rel']['data'])) | |
177 | { | |
178 | $rel = array_unique(SimplePie_Misc::space_seperated_tokens(strtolower($link['attribs']['rel']['data']))); | |
179 | ||
180 | if ($this->base_location < $link['offset']) | |
181 | { | |
182 | $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base); | |
183 | } | |
184 | else | |
185 | { | |
186 | $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base); | |
187 | } | |
188 | ||
189 | if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && !empty($link['attribs']['type']['data']) && in_array(strtolower(SimplePie_Misc::parse_mime($link['attribs']['type']['data'])), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href])) | |
190 | { | |
191 | $this->checked_feeds++; | |
192 | $headers = array( | |
193 | 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', | |
194 | ); | |
195 | $feed = new $this->file_class($href, $this->timeout, 5, $headers, $this->useragent); | |
196 | if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) | |
197 | { | |
198 | $feeds[$href] = $feed; | |
199 | } | |
200 | } | |
201 | $done[] = $href; | |
202 | } | |
203 | } | |
204 | ||
205 | if (!empty($feeds)) | |
206 | { | |
207 | return array_values($feeds); | |
208 | } | |
209 | else | |
210 | { | |
211 | return null; | |
212 | } | |
213 | } | |
214 | ||
215 | public function get_links() | |
216 | { | |
217 | $links = SimplePie_Misc::get_element('a', $this->file->body); | |
218 | foreach ($links as $link) | |
219 | { | |
220 | if (isset($link['attribs']['href']['data'])) | |
221 | { | |
222 | $href = trim($link['attribs']['href']['data']); | |
223 | $parsed = SimplePie_Misc::parse_url($href); | |
224 | if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme'])) | |
225 | { | |
226 | if ($this->base_location < $link['offset']) | |
227 | { | |
228 | $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base); | |
229 | } | |
230 | else | |
231 | { | |
232 | $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base); | |
233 | } | |
234 | ||
235 | $current = SimplePie_Misc::parse_url($this->file->url); | |
236 | ||
237 | if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority']) | |
238 | { | |
239 | $this->local[] = $href; | |
240 | } | |
241 | else | |
242 | { | |
243 | $this->elsewhere[] = $href; | |
244 | } | |
245 | } | |
246 | } | |
247 | } | |
248 | $this->local = array_unique($this->local); | |
249 | $this->elsewhere = array_unique($this->elsewhere); | |
250 | if (!empty($this->local) || !empty($this->elsewhere)) | |
251 | { | |
252 | return true; | |
253 | } | |
254 | return null; | |
255 | } | |
256 | ||
257 | public function extension(&$array) | |
258 | { | |
259 | foreach ($array as $key => $value) | |
260 | { | |
261 | if ($this->checked_feeds === $this->max_checked_feeds) | |
262 | { | |
263 | break; | |
264 | } | |
265 | if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml'))) | |
266 | { | |
267 | $this->checked_feeds++; | |
268 | ||
269 | $headers = array( | |
270 | 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', | |
271 | ); | |
272 | $feed = new $this->file_class($value, $this->timeout, 5, $headers, $this->useragent); | |
273 | if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) | |
274 | { | |
275 | return $feed; | |
276 | } | |
277 | else | |
278 | { | |
279 | unset($array[$key]); | |
280 | } | |
281 | } | |
282 | } | |
283 | return null; | |
284 | } | |
285 | ||
286 | public function body(&$array) | |
287 | { | |
288 | foreach ($array as $key => $value) | |
289 | { | |
290 | if ($this->checked_feeds === $this->max_checked_feeds) | |
291 | { | |
292 | break; | |
293 | } | |
294 | if (preg_match('/(rss|rdf|atom|xml)/i', $value)) | |
295 | { | |
296 | $this->checked_feeds++; | |
297 | $headers = array( | |
298 | 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', | |
299 | ); | |
300 | $feed = new $this->file_class($value, $this->timeout, 5, null, $this->useragent); | |
301 | if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) | |
302 | { | |
303 | return $feed; | |
304 | } | |
305 | else | |
306 | { | |
307 | unset($array[$key]); | |
308 | } | |
309 | } | |
310 | } | |
311 | return null; | |
312 | } | |
313 | } | |
314 |