PluginProbe
FeedWordPress / 2010.0905
FeedWordPress v2010.0905
trunk 0.8 0.9 0.91 0.95 0.96 0.97 0.98 0.981 0.99 0.991 0.992 0.993 2008.1030 2008.1101 2008.1105 2008.1214 2009.0612 2009.0613 2009.0618 2009.0707 2009.1111 2009.1112 2010.0127 2010.0528 All 65 releases
feedwordpress / feedfinder.class.php

feedfinder.class.php in FeedWordPress 2010.0905, at feedfinder.class.php

313 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * class FeedFinder: find likely feeds using autodetection and/or guesswork
4 * @version 2010.0622
5 * @uses SimplePie_Misc
6 */
7
8 if (!class_exists('SimplePie')) :
9 require_once(ABSPATH . WPINC . '/class-simplepie.php');
10 endif;
11 require_once(dirname(__FILE__).'/feedwordpresshtml.class.php');
12
13 class FeedFinder {
14 var $uri = NULL;
15 var $_cache_uri = NULL;
16
17 var $verify = FALSE;
18 var $fallbacks = 3;
19
20 var $_response = NULL;
21 var $_data = NULL;
22 var $_error = NULL;
23 var $_head = NULL;
24
25 # -- Recognition patterns
26 var $_feed_types = array(
27 'application/rss+xml',
28 'text/xml',
29 'application/atom+xml',
30 'application/x.atom+xml',
31 'application/x-atom+xml'
32 );
33 var $_feed_markers = array('\\<feed', '\\<rss', 'xmlns="http://purl.org/rss/1.0');
34 var $_html_markers = array('\\<html');
35 var $_opml_markers = array('\\<opml', '\\<outline');
36 var $_obvious_feed_url = array('[./]rss', '[./]rdf', '[./]atom', '[./]feed', '\.xml');
37 var $_maybe_feed_url = array ('rss', 'rdf', 'atom', 'feed', 'xml');
38
39 function FeedFinder ($uri = NULL, $verify = TRUE, $fallbacks = 3) {
40 $this->uri = $uri; $this->verify = $verify;
41 $this->fallbacks = $fallbacks;
42 } /* FeedFinder::FeedFinder () */
43
44 function find ($uri = NULL) {
45 $ret = array ();
46 if (!is_null($this->data($uri))) :
47 if ($this->is_opml($uri)) :
48 $href = $this->_opml_rss_uris();
49 else :
50 if ($this->is_feed($uri)) :
51 $href = array($this->uri);
52 else :
53 // Assume that we have HTML or XHTML (even if we don't, who's it gonna hurt?)
54 // Autodiscovery is the preferred method
55 $href = $this->_link_rel_feeds();
56
57 // ... but we'll also take the little orange buttons
58 if ($this->fallbacks > 0) :
59 $href = array_merge($href, $this->_a_href_feeds(TRUE));
60 endif;
61
62 // If all that failed, look harder
63 if ($this->fallbacks > 1) :
64 if (count($href) == 0) :
65 $href = $this->_a_href_feeds(FALSE);
66 endif;
67 endif;
68
69 // Our search may turn up duplicate URIs. We only need to do any given URI once.
70 // Props to Camilo <http://projects.radgeek.com/2008/12/14/feedwordpress-20081214/#comment-20090122160414>
71 $href = array_unique($href);
72 endif;
73
74 // Try some clever URL little tricks before we go
75 if ($this->fallbacks > 2) :
76 $href = array_merge($href, $this->_url_manipulation_feeds());
77 endif;
78 endif;
79
80 $href = array_unique($href);
81
82 // Verify feeds and resolve relative URIs
83 foreach ($href as $u) :
84 $the_uri = SimplePie_Misc::absolutize_url($u, $this->uri);
85 if ($this->verify and ($u != $this->uri and $the_uri != $this->uri)) :
86 $feed = new FeedFinder($the_uri);
87 if ($feed->is_feed()) : $ret[] = $the_uri; endif;
88 unset($feed);
89 else :
90 $ret[] = $the_uri;
91 endif;
92 endforeach;
93 endif;
94
95 return array_values($ret);
96 } /* FeedFinder::find () */
97
98 function data ($uri = NULL) {
99 $this->_get($uri);
100 return $this->_data;
101 } /* FeedFinder::data () */
102
103 function upload_data ($data) {
104 $this->uri = 'tag:localhost';
105 $this->_data = $data;
106 } /* FeedFinder::upload_data () */
107
108 function status ($uri = NULL) {
109 $this->_get($uri);
110
111 if (!is_wp_error($this->_response) and isset($this->_response['response']['code'])) :
112 $ret = $this->_response['response']['code'];
113 else :
114 $ret = NULL;
115 endif;
116 return $ret;
117 }
118
119 function error ($index = NULL) {
120 $message = NULL;
121 if (count($this->_error) > 0) :
122 if (is_scalar($index) and !is_null($index)) :
123 $message = $this->_error[$index];
124 else :
125 $message = implode(" / ", $this->_error)."\n";
126 endif;
127 endif;
128 return $message;
129 }
130
131 function is_feed ($uri = NULL) {
132 $data = $this->data($uri);
133
134 return (
135 preg_match (
136 "\007(".implode('|',$this->_feed_markers).")\007i",
137 $data
138 ) and !preg_match (
139 "\007(".implode('|',$this->_html_markers).")\007i",
140 $data
141 )
142 );
143 } /* FeedFinder::is_feed () */
144
145 function is_opml ($uri = NULL) {
146 $data = $this->data($uri);
147 return (
148 preg_match (
149 "\007(".implode('|',$this->_opml_markers).")\007i",
150 $data
151 )
152 );
153 } /* FeedFinder::is_opml () */
154
155 # --- Private methods ---
156 function _get ($uri = NULL) {
157 if ($uri) $this->uri = $uri;
158
159 // Is the result not yet cached?
160 if ($this->uri != 'tag:localhost' and $this->_cache_uri !== $this->uri) :
161 $headers['Connection'] = 'close';
162 $headers['Accept'] = 'application/atom+xml application/rdf+xml application/rss+xml application/xml text/html */*';
163 $headers['User-Agent'] = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress';
164
165 // Use WordPress API function
166 $client = wp_remote_request($this->uri, array(
167 'headers' => $headers,
168 'timeout' => FEEDWORDPRESS_FETCH_TIME_OUT,
169 ));
170
171 $this->_response = $client;
172 if (is_wp_error($client)) :
173 $this->_data = NULL;
174 $this->_error = $client->get_error_messages();
175 else :
176 $this->_data = $client['body'];
177 $this->_error = NULL;
178 endif;
179
180 // Kilroy was here
181 $this->_cache_uri = $this->uri;
182 endif;
183 } /* FeedFinder::_get () */
184
185 function _opml_rss_uris () {
186 // Really we should parse the XML and use the structure to
187 // return something intelligent to programs that want to use it
188 // Oh babe! maybe some day...
189
190 $opml = $this->data();
191
192 $rx = FeedWordPressHTML::attributeRegex('outline', 'xmlUrl');
193 if (preg_match_all($rx, $opml, $matches, PREG_SET_ORDER)) :
194 foreach ($matches as $m) :
195 $match = FeedWordPressHTML::attributeMatch($m);
196 $r[] = $match['value'];
197 endforeach;
198 endif;
199 return $r;
200 } /* FeedFinder::_opml_rss_uris () */
201
202 function _link_rel_feeds () {
203 $links = $this->_tags('link');
204 $link_count = count($links);
205
206 // now figure out which one points to the RSS file
207 $href = array ();
208 for ($n=0; $n<$link_count; $n++) {
209 if (strtolower($links[$n]['rel']) == 'alternate') {
210 if (in_array(strtolower($links[$n]['type']), $this->_feed_types)) {
211 $href[] = $links[$n]['href'];
212 } /* if */
213 } /* if */
214 } /* for */
215 return $href;
216 } /* FeedFinder::_link_rel_feeds () */
217
218 function _a_href_feeds ($obvious = TRUE) {
219 $pattern = ($obvious ? $this->_obvious_feed_url : $this->_maybe_feed_url);
220
221 $links = $this->_tags('a');
222 $link_count = count($links);
223
224 // now figure out which one points to the RSS file
225 $href = array ();
226 for ($n=0; $n<$link_count; $n++) {
227 if (preg_match("\007(".implode('|',$pattern).")\007i", $links[$n]['href'])) {
228 $href[] = $links[$n]['href'];
229 } /* if */
230 } /* for */
231 return $href;
232 } /* FeedFinder::_link_a_href_feeds () */
233
234 function _url_manipulation_feeds () {
235 $href = array();
236
237 // check for HTTP GET parameters that look feed-like.
238 $bits = parse_url($this->uri);
239 foreach (array('rss', 'rss2', 'atom', 'rdf') as $format) :
240 if (isset($bits['query']) and (strlen($bits['query']) > 0)) :
241 $newQuery = preg_replace('/([?&=])(rss2?|atom|rdf)/i', '$1'.$format, $bits['query']);
242 else :
243 $newQuery = NULL;
244 endif;
245
246 if (isset($bits['path']) and (strlen($bits['path']) > 0)) :
247 $newPath = preg_replace('!([/.])(rss2?|atom|rdf)!i', '$1'.$format, $bits['path']);
248 else :
249 $newPath = NULL;
250 endif;
251
252 // Reassemble, check and return
253 $credentials = '';
254 if (isset($bits['user'])) :
255 $credentials = $bits['user'];
256 if (isset($bits['pass'])) :
257 $credentials .= ':'.$bits['pass'];
258 endif;
259 $credentials .= '@';
260 endif;
261
262 // Variations on a theme
263 $newUrl[0] = (''
264 .(isset($bits['scheme']) ? $bits['scheme'].':' : '')
265 .(isset($bits['host']) ? '//'.$credentials.$bits['host'] : '')
266 .(!is_null($newPath) ? $newPath : '')
267 .(!is_null($newQuery) ? '?'.$newQuery : '')
268 .(isset($bits['fragment']) ? '#'.$bits['fragment'] : '')
269 );
270 $newUrl[1] = (''
271 .(isset($bits['scheme']) ? $bits['scheme'].':' : '')
272 .(isset($bits['host']) ? '//'.$credentials.$bits['host'] : '')
273 .(!is_null($newPath) ? $newPath : '')
274 .(isset($bits['query']) ? '?'.$bits['query'] : '')
275 .(isset($bits['fragment']) ? '#'.$bits['fragment'] : '')
276 );
277 $newUrl[2] = (''
278 .(isset($bits['scheme']) ? $bits['scheme'].':' : '')
279 .(isset($bits['host']) ? '//'.$credentials.$bits['host'] : '')
280 .(isset($bits['path']) ? $bits['path'] : '')
281 .(!is_null($newQuery) ? '?'.$newQuery : '')
282 .(isset($bits['fragment']) ? '#'.$bits['fragment'] : '')
283 );
284 $href = array_merge($href, $newUrl);
285 endforeach;
286 return array_unique($href);
287 } /* FeedFinder::_url_manipulation_feeds () */
288
289 function _tags ($tag) {
290 $html = $this->data();
291
292 // search through the HTML, save all <link> tags
293 // and store each link's attributes in an associative array
294 preg_match_all('/<'.$tag.'\s+(.*?)\s*\/?>/si', $html, $matches);
295 $links = $matches[1];
296 $ret = array();
297 $link_count = count($links);
298 for ($n=0; $n<$link_count; $n++) {
299 $attributes = preg_split('/\s+/s', $links[$n]);
300 foreach($attributes as $attribute) {
301 $att = preg_split('/\s*=\s*/s', $attribute, 2);
302 if (isset($att[1])) {
303 $att[1] = preg_replace('/([\'"]?)(.*)\1/', '$2', $att[1]);
304 $final_link[strtolower($att[0])] = $att[1];
305 } /* if */
306 } /* foreach */
307 $ret[$n] = $final_link;
308 } /* for */
309 return $ret;
310 } /* FeedFinder::_tags () */
311 } /* class FeedFinder */
312
313