PluginProbe
FeedWordPress / 2013.0504
FeedWordPress v2013.0504
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
← All changes | feedfinder.class.php +211 -43 2010.05282013.0504 View file →
@@ -1,15 +1,24 @@
1 1 <?php
2 -################################################################################
3 -## class FeedFinder: find likely feeds using autodetection and/or guesswork ####
4 -################################################################################
2 +/**
3 + * class FeedFinder: find likely feeds using autodetection and/or guesswork
4 + * @version 2010.0622
5 + * @uses SimplePie_Misc
6 + */
5 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 +
6 13 class FeedFinder {
7 14 var $uri = NULL;
15 + var $credentials = NULL;
8 16 var $_cache_uri = NULL;
9 17
10 18 var $verify = FALSE;
11 -
19 + var $fallbacks = 3;
20 +
12 21 var $_response = NULL;
13 22 var $_data = NULL;
14 23 var $_error = NULL;
15 24 var $_head = NULL;
@@ -23,56 +32,126 @@
23 32 'application/x-atom+xml'
24 33 );
25 34 var $_feed_markers = array('\\<feed', '\\<rss', 'xmlns="http://purl.org/rss/1.0');
26 35 var $_html_markers = array('\\<html');
36 + var $_opml_markers = array('\\<opml', '\\<outline');
27 37 var $_obvious_feed_url = array('[./]rss', '[./]rdf', '[./]atom', '[./]feed', '\.xml');
28 38 var $_maybe_feed_url = array ('rss', 'rdf', 'atom', 'feed', 'xml');
29 39
30 - function FeedFinder ($uri = NULL, $verify = TRUE) {
40 + function FeedFinder ($uri = NULL, $params = array(), $fallbacks = 3) {
41 + if (is_bool($params)) :
42 + $params = array("verify" => $params);
43 + endif;
44 +
45 + $params = wp_parse_args($params, array(
46 + "verify" => true,
47 + "authentication" => NULL,
48 + "username" => NULL,
49 + "password" => NULL,
50 + ));
51 + $verify = $params['verify'];
52 + $this->credentials = array(
53 + "authentication" => $params['authentication'],
54 + "username" => $params['username'],
55 + "password" => $params['password'],
56 + );
57 +
31 58 $this->uri = $uri; $this->verify = $verify;
59 + $this->fallbacks = $fallbacks;
32 60 } /* FeedFinder::FeedFinder () */
33 61
34 - function find ($uri = NULL) {
62 + function find ($uri = NULL, $params = array()) {
63 + $params = wp_parse_args($params, array( // Defaults
64 + "authentication" => -1,
65 + "username" => NULL,
66 + "password" => NULL,
67 + ));
68 +
69 + // Equivalents
70 + if ($params['authentication']=='-') :
71 + $params['authentication'] = NULL;
72 + $params['username'] = NULL;
73 + $params['password'] = NULL;
74 + endif;
75 +
76 + // Set/reset
77 + if ($params['authentication'] != -1) :
78 + $this->credentials = array(
79 + "authentication" => $params['authentication'],
80 + "username" => $params['username'],
81 + "password" => $params['password'],
82 + );
83 + endif;
84 +
35 85 $ret = array ();
36 - if (!is_null($this->data($uri))) {
37 - if ($this->is_feed($uri)) {
38 - $ret = array($this->uri);
39 - } else {
40 - // Assume that we have HTML or XHTML (even if we don't, who's it gonna hurt?)
41 - // Autodiscovery is the preferred method
42 - $href = $this->_link_rel_feeds();
43 -
44 - // ... but we'll also take the little orange buttons
45 - $href = array_merge($href, $this->_a_href_feeds(TRUE));
46 -
47 - // If all that failed, look harder
48 - if (count($href) == 0) $href = $this->_a_href_feeds(FALSE);
86 + if (!is_null($this->data($uri))) :
87 + if ($this->is_opml($uri)) :
88 + $href = $this->_opml_rss_uris();
89 + else :
90 + if ($this->is_feed($uri)) :
91 + $href = array($this->uri);
92 + else :
93 + // Assume that we have HTML or XHTML (even if we don't, who's
94 + // it gonna hurt?) Autodiscovery is the preferred method.
95 + $href = $this->_link_rel_feeds();
96 +
97 + // ... but we'll also take the little orange buttons
98 + if ($this->fallbacks > 0) :
99 + $href = array_merge($href, $this->_a_href_feeds(TRUE));
100 + endif;
101 +
102 + // If all that failed, look harder
103 + if ($this->fallbacks > 1) :
104 + if (count($href) == 0) :
105 + $href = $this->_a_href_feeds(FALSE);
106 + endif;
107 + endif;
108 +
109 + // Our search may turn up duplicate URIs. We only need to do
110 + // any given URI once. Props to Camilo <http://projects.radgeek.com/2008/12/14/feedwordpress-20081214/#comment-20090122160414>
111 + $href = array_unique($href);
112 + endif;
49 113
50 - // Our search may turn up duplicate URIs. We only need to do any given URI once.
51 - // Props to Camilo <http://projects.radgeek.com/2008/12/14/feedwordpress-20081214/#comment-20090122160414>
52 - $href = array_unique($href);
114 + // Try some clever URL little tricks before we go
115 + if ($this->fallbacks > 2) :
116 + $href = array_merge($href, $this->_url_manipulation_feeds());
117 + endif;
118 + endif;
119 +
120 + $href = array_unique($href);
53 121
54 - // Verify feeds and resolve relative URIs
55 - foreach ($href as $u) {
56 - $the_uri = Relative_URI::resolve($u, $this->uri);
57 - if ($this->verify) {
58 - $feed = new FeedFinder($the_uri);
59 - if ($feed->is_feed()) $ret[] = $the_uri;
60 - unset($feed);
61 - } else {
62 - $ret[] = $the_uri;
63 - }
64 - } /* foreach */
65 - } /* if */
66 - } /* if */
67 - return array_unique($ret);
122 + // Verify feeds and resolve relative URIs
123 + foreach ($href as $u) :
124 + $the_uri = SimplePie_Misc::absolutize_url($u, $this->uri);
125 + if ($this->verify and ($u != $this->uri and $the_uri != $this->uri)) :
126 + $feed = new FeedFinder($the_uri, $this->credentials);
127 + if ($feed->is_feed()) : $ret[] = $the_uri; endif;
128 + unset($feed);
129 + else :
130 + $ret[] = $the_uri;
131 + endif;
132 + endforeach;
133 + endif;
134 +
135 + if ($this->is_401($uri)) :
136 + $ret = array_merge(array(
137 + new WP_Error('http_request_failed', '401 Not authorized', array("uri" => $this->uri, "status" => 401)),
138 + ), $ret);
139 + endif;
140 +
141 + return array_values($ret);
68 142 } /* FeedFinder::find () */
69 143
70 144 function data ($uri = NULL) {
71 145 $this->_get($uri);
72 146 return $this->_data;
73 - }
147 + } /* FeedFinder::data () */
74 148
149 + function upload_data ($data) {
150 + $this->uri = 'tag:localhost';
151 + $this->_data = $data;
152 + } /* FeedFinder::upload_data () */
153 +
75 154 function status ($uri = NULL) {
76 155 $this->_get($uri);
77 156
78 157 if (!is_wp_error($this->_response) and isset($this->_response['response']['code'])) :
@@ -94,8 +173,12 @@
94 173 endif;
95 174 return $message;
96 175 }
97 176
177 + function is_401 ($uri = NULL) {
178 + return (intval($this->status($uri))==401);
179 + } /* FeedFinder::is_401 () */
180 +
98 181 function is_feed ($uri = NULL) {
99 182 $data = $this->data($uri);
100 183
101 184 return (
@@ -108,22 +191,35 @@
108 191 )
109 192 );
110 193 } /* FeedFinder::is_feed () */
111 194
195 + function is_opml ($uri = NULL) {
196 + $data = $this->data($uri);
197 + return (
198 + preg_match (
199 + "\007(".implode('|',$this->_opml_markers).")\007i",
200 + $data
201 + )
202 + );
203 + } /* FeedFinder::is_opml () */
204 +
112 205 # --- Private methods ---
113 206 function _get ($uri = NULL) {
114 207 if ($uri) $this->uri = $uri;
115 208
116 209 // Is the result not yet cached?
117 - if ($this->_cache_uri !== $this->uri) :
210 + if ($this->uri != 'tag:localhost' and $this->_cache_uri !== $this->uri) :
118 211 $headers['Connection'] = 'close';
119 212 $headers['Accept'] = 'application/atom+xml application/rdf+xml application/rss+xml application/xml text/html */*';
120 213 $headers['User-Agent'] = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress';
121 214
122 215 // Use WordPress API function
123 - $client = wp_remote_request($this->uri, array(
216 + $client = wp_remote_request($this->uri, array_merge(
217 + $this->credentials,
218 + array(
124 219 'headers' => $headers,
125 - 'timeout' => FEEDWORDPRESS_FETCH_TIME_OUT,
220 + 'timeout' => FeedWordPress::fetch_timeout(),
221 + )
126 222 ));
127 223
128 224 $this->_response = $client;
129 225 if (is_wp_error($client)) :
@@ -138,8 +234,25 @@
138 234 $this->_cache_uri = $this->uri;
139 235 endif;
140 236 } /* FeedFinder::_get () */
141 237
238 + function _opml_rss_uris () {
239 + // Really we should parse the XML and use the structure to
240 + // return something intelligent to programs that want to use it
241 + // Oh babe! maybe some day...
242 +
243 + $opml = $this->data();
244 +
245 + $rx = FeedWordPressHTML::attributeRegex('outline', 'xmlUrl');
246 + if (preg_match_all($rx, $opml, $matches, PREG_SET_ORDER)) :
247 + foreach ($matches as $m) :
248 + $match = FeedWordPressHTML::attributeMatch($m);
249 + $r[] = $match['value'];
250 + endforeach;
251 + endif;
252 + return $r;
253 + } /* FeedFinder::_opml_rss_uris () */
254 +
142 255 function _link_rel_feeds () {
143 256 $links = $this->_tags('link');
144 257 $link_count = count($links);
145 258
@@ -152,9 +265,9 @@
152 265 } /* if */
153 266 } /* if */
154 267 } /* for */
155 268 return $href;
156 - }
269 + } /* FeedFinder::_link_rel_feeds () */
157 270
158 271 function _a_href_feeds ($obvious = TRUE) {
159 272 $pattern = ($obvious ? $this->_obvious_feed_url : $this->_maybe_feed_url);
160 273
@@ -168,10 +281,65 @@
168 281 $href[] = $links[$n]['href'];
169 282 } /* if */
170 283 } /* for */
171 284 return $href;
172 - }
285 + } /* FeedFinder::_link_a_href_feeds () */
173 286
287 + function _url_manipulation_feeds () {
288 + $href = array();
289 +
290 + // check for HTTP GET parameters that look feed-like.
291 + $bits = parse_url($this->uri);
292 + foreach (array('rss', 'rss2', 'atom', 'rdf') as $format) :
293 + if (isset($bits['query']) and (strlen($bits['query']) > 0)) :
294 + $newQuery = preg_replace('/([?&=])(rss2?|atom|rdf)/i', '$1'.$format, $bits['query']);
295 + else :
296 + $newQuery = NULL;
297 + endif;
298 +
299 + if (isset($bits['path']) and (strlen($bits['path']) > 0)) :
300 + $newPath = preg_replace('!([/.])(rss2?|atom|rdf)!i', '$1'.$format, $bits['path']);
301 + else :
302 + $newPath = NULL;
303 + endif;
304 +
305 + // Reassemble, check and return
306 + $credentials = '';
307 + if (isset($bits['user'])) :
308 + $credentials = $bits['user'];
309 + if (isset($bits['pass'])) :
310 + $credentials .= ':'.$bits['pass'];
311 + endif;
312 + $credentials .= '@';
313 + endif;
314 +
315 + // Variations on a theme
316 + $newUrl[0] = (''
317 + .(isset($bits['scheme']) ? $bits['scheme'].':' : '')
318 + .(isset($bits['host']) ? '//'.$credentials.$bits['host'] : '')
319 + .(!is_null($newPath) ? $newPath : '')
320 + .(!is_null($newQuery) ? '?'.$newQuery : '')
321 + .(isset($bits['fragment']) ? '#'.$bits['fragment'] : '')
322 + );
323 + $newUrl[1] = (''
324 + .(isset($bits['scheme']) ? $bits['scheme'].':' : '')
325 + .(isset($bits['host']) ? '//'.$credentials.$bits['host'] : '')
326 + .(!is_null($newPath) ? $newPath : '')
327 + .(isset($bits['query']) ? '?'.$bits['query'] : '')
328 + .(isset($bits['fragment']) ? '#'.$bits['fragment'] : '')
329 + );
330 + $newUrl[2] = (''
331 + .(isset($bits['scheme']) ? $bits['scheme'].':' : '')
332 + .(isset($bits['host']) ? '//'.$credentials.$bits['host'] : '')
333 + .(isset($bits['path']) ? $bits['path'] : '')
334 + .(!is_null($newQuery) ? '?'.$newQuery : '')
335 + .(isset($bits['fragment']) ? '#'.$bits['fragment'] : '')
336 + );
337 + $href = array_merge($href, $newUrl);
338 + endforeach;
339 + return array_unique($href);
340 + } /* FeedFinder::_url_manipulation_feeds () */
341 +
174 342 function _tags ($tag) {
175 343 $html = $this->data();
176 344
177 345 // search through the HTML, save all <link> tags
@@ -191,7 +359,7 @@
191 359 } /* foreach */
192 360 $ret[$n] = $final_link;
193 361 } /* for */
194 362 return $ret;
195 - }
363 + } /* FeedFinder::_tags () */
196 364 } /* class FeedFinder */
197 365