PluginProbe
FeedWordPress / 2012.1212
FeedWordPress v2012.1212
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 +232 -51 2009.11122012.1212 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,61 +32,131 @@
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 - $feed = NULL;
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 - if (isset($this->_response->status)) :
79 - $ret = $this->_response->status;
157 + if (!is_wp_error($this->_response) and isset($this->_response['response']['code'])) :
158 + $ret = $this->_response['response']['code'];
80 159 else :
81 160 $ret = NULL;
82 161 endif;
83 162 return $ret;
@@ -82,12 +161,24 @@
82 161 endif;
83 162 return $ret;
84 163 }
85 164
86 - function error () {
87 - return $this->_error;
165 + function error ($index = NULL) {
166 + $message = NULL;
167 + if (count($this->_error) > 0) :
168 + if (is_scalar($index) and !is_null($index)) :
169 + $message = $this->_error[$index];
170 + else :
171 + $message = implode(" / ", $this->_error)."\n";
172 + endif;
173 + endif;
174 + return $message;
88 175 }
89 176
177 + function is_401 ($uri = NULL) {
178 + return (intval($this->status($uri))==401);
179 + } /* FeedFinder::is_401 () */
180 +
90 181 function is_feed ($uri = NULL) {
91 182 $data = $this->data($uri);
92 183
93 184 return (
@@ -100,27 +191,45 @@
100 191 )
101 192 );
102 193 } /* FeedFinder::is_feed () */
103 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 +
104 205 # --- Private methods ---
105 206 function _get ($uri = NULL) {
106 207 if ($uri) $this->uri = $uri;
107 208
108 209 // Is the result not yet cached?
109 - if ($this->_cache_uri !== $this->uri) :
210 + if ($this->uri != 'tag:localhost' and $this->_cache_uri !== $this->uri) :
110 211 $headers['Connection'] = 'close';
111 212 $headers['Accept'] = 'application/atom+xml application/rdf+xml application/rss+xml application/xml text/html */*';
112 213 $headers['User-Agent'] = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress';
113 214
114 - // Use function provided by MagpieRSS package
115 - $client = _fetch_remote_file($this->uri, $headers);
116 - if (isset($client->error)) :
117 - $this->_error = $client->error;
215 + // Use WordPress API function
216 + $client = wp_remote_request($this->uri, array_merge(
217 + $this->credentials,
218 + array(
219 + 'headers' => $headers,
220 + 'timeout' => FeedWordPress::fetch_timeout(),
221 + )
222 + ));
223 +
224 + $this->_response = $client;
225 + if (is_wp_error($client)) :
226 + $this->_data = NULL;
227 + $this->_error = $client->get_error_messages();
118 228 else :
229 + $this->_data = $client['body'];
119 230 $this->_error = NULL;
120 231 endif;
121 - $this->_response = $client;
122 - $this->_data = $client->results;
123 232
124 233 // Kilroy was here
125 234 $this->_cache_uri = $this->uri;
126 235 endif;
@@ -125,8 +234,25 @@
125 234 $this->_cache_uri = $this->uri;
126 235 endif;
127 236 } /* FeedFinder::_get () */
128 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 +
129 255 function _link_rel_feeds () {
130 256 $links = $this->_tags('link');
131 257 $link_count = count($links);
132 258
@@ -139,9 +265,9 @@
139 265 } /* if */
140 266 } /* if */
141 267 } /* for */
142 268 return $href;
143 - }
269 + } /* FeedFinder::_link_rel_feeds () */
144 270
145 271 function _a_href_feeds ($obvious = TRUE) {
146 272 $pattern = ($obvious ? $this->_obvious_feed_url : $this->_maybe_feed_url);
147 273
@@ -155,10 +281,65 @@
155 281 $href[] = $links[$n]['href'];
156 282 } /* if */
157 283 } /* for */
158 284 return $href;
159 - }
285 + } /* FeedFinder::_link_a_href_feeds () */
160 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 +
161 342 function _tags ($tag) {
162 343 $html = $this->data();
163 344
164 345 // search through the HTML, save all <link> tags
@@ -178,7 +359,7 @@
178 359 } /* foreach */
179 360 $ret[$n] = $final_link;
180 361 } /* for */
181 362 return $ret;
182 - }
363 + } /* FeedFinder::_tags () */
183 364 } /* class FeedFinder */
184 365