PluginProbe
FeedWordPress / 2017.0913
FeedWordPress v2017.0913
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 +236 -51 2009.06132017.0913 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,135 @@
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 __construct( $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 FeedFinder( $uri = NULL, $params = array(), $fallbacks = 3 ) {
63 + self::__construct( $uri, $params, $fallbacks );
64 + }
65 +
66 + function find ($uri = NULL, $params = array()) {
67 + $params = wp_parse_args($params, array( // Defaults
68 + "authentication" => -1,
69 + "username" => NULL,
70 + "password" => NULL,
71 + ));
72 +
73 + // Equivalents
74 + if ($params['authentication']=='-') :
75 + $params['authentication'] = NULL;
76 + $params['username'] = NULL;
77 + $params['password'] = NULL;
78 + endif;
79 +
80 + // Set/reset
81 + if ($params['authentication'] != -1) :
82 + $this->credentials = array(
83 + "authentication" => $params['authentication'],
84 + "username" => $params['username'],
85 + "password" => $params['password'],
86 + );
87 + endif;
88 +
35 89 $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);
90 + if (!is_null($this->data($uri))) :
91 + if ($this->is_opml($uri)) :
92 + $href = $this->_opml_rss_uris();
93 + else :
94 + if ($this->is_feed($uri)) :
95 + $href = array($this->uri);
96 + else :
97 + // Assume that we have HTML or XHTML (even if we don't, who's
98 + // it gonna hurt?) Autodiscovery is the preferred method.
99 + $href = $this->_link_rel_feeds();
100 +
101 + // ... but we'll also take the little orange buttons
102 + if ($this->fallbacks > 0) :
103 + $href = array_merge($href, $this->_a_href_feeds(TRUE));
104 + endif;
105 +
106 + // If all that failed, look harder
107 + if ($this->fallbacks > 1) :
108 + if (count($href) == 0) :
109 + $href = $this->_a_href_feeds(FALSE);
110 + endif;
111 + endif;
112 +
113 + // Our search may turn up duplicate URIs. We only need to do
114 + // any given URI once. Props to Camilo <http://projects.radgeek.com/2008/12/14/feedwordpress-20081214/#comment-20090122160414>
115 + $href = array_unique($href);
116 + endif;
49 117
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);
118 + // Try some clever URL little tricks before we go
119 + if ($this->fallbacks > 2) :
120 + $href = array_merge($href, $this->_url_manipulation_feeds());
121 + endif;
122 + endif;
123 +
124 + $href = array_unique($href);
53 125
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);
126 + // Verify feeds and resolve relative URIs
127 + foreach ($href as $u) :
128 + $the_uri = SimplePie_Misc::absolutize_url($u, $this->uri);
129 + if ($this->verify and ($u != $this->uri and $the_uri != $this->uri)) :
130 + $feed = new FeedFinder($the_uri, $this->credentials);
131 + if ($feed->is_feed()) : $ret[] = $the_uri; endif;
132 + unset($feed);
133 + else :
134 + $ret[] = $the_uri;
135 + endif;
136 + endforeach;
137 + endif;
138 +
139 + if ($this->is_401($uri)) :
140 + $ret = array_merge(array(
141 + new WP_Error('http_request_failed', '401 Not authorized', array("uri" => $this->uri, "status" => 401)),
142 + ), $ret);
143 + endif;
144 +
145 + return array_values($ret);
68 146 } /* FeedFinder::find () */
69 147
70 148 function data ($uri = NULL) {
71 149 $this->_get($uri);
72 150 return $this->_data;
73 - }
151 + } /* FeedFinder::data () */
74 152
153 + function upload_data ($data) {
154 + $this->uri = 'tag:localhost';
155 + $this->_data = $data;
156 + } /* FeedFinder::upload_data () */
157 +
75 158 function status ($uri = NULL) {
76 159 $this->_get($uri);
77 160
78 - if (isset($this->_response->status)) :
79 - $ret = $this->_response->status;
161 + if (!is_wp_error($this->_response) and isset($this->_response['response']['code'])) :
162 + $ret = $this->_response['response']['code'];
80 163 else :
81 164 $ret = NULL;
82 165 endif;
83 166 return $ret;
@@ -82,12 +165,24 @@
82 165 endif;
83 166 return $ret;
84 167 }
85 168
86 - function error () {
87 - return $this->_error;
169 + function error ($index = NULL) {
170 + $message = NULL;
171 + if (count($this->_error) > 0) :
172 + if (is_scalar($index) and !is_null($index)) :
173 + $message = $this->_error[$index];
174 + else :
175 + $message = implode(" / ", $this->_error)."\n";
176 + endif;
177 + endif;
178 + return $message;
88 179 }
89 180
181 + function is_401 ($uri = NULL) {
182 + return (intval($this->status($uri))==401);
183 + } /* FeedFinder::is_401 () */
184 +
90 185 function is_feed ($uri = NULL) {
91 186 $data = $this->data($uri);
92 187
93 188 return (
@@ -100,27 +195,45 @@
100 195 )
101 196 );
102 197 } /* FeedFinder::is_feed () */
103 198
199 + function is_opml ($uri = NULL) {
200 + $data = $this->data($uri);
201 + return (
202 + preg_match (
203 + "\007(".implode('|',$this->_opml_markers).")\007i",
204 + $data
205 + )
206 + );
207 + } /* FeedFinder::is_opml () */
208 +
104 209 # --- Private methods ---
105 210 function _get ($uri = NULL) {
106 211 if ($uri) $this->uri = $uri;
107 212
108 213 // Is the result not yet cached?
109 - if ($this->_cache_uri !== $this->uri) :
214 + if ($this->uri != 'tag:localhost' and $this->_cache_uri !== $this->uri) :
110 215 $headers['Connection'] = 'close';
111 216 $headers['Accept'] = 'application/atom+xml application/rdf+xml application/rss+xml application/xml text/html */*';
112 217 $headers['User-Agent'] = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress';
113 218
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;
219 + // Use WordPress API function
220 + $client = wp_remote_request($this->uri, array_merge(
221 + $this->credentials,
222 + array(
223 + 'headers' => $headers,
224 + 'timeout' => FeedWordPress::fetch_timeout(),
225 + )
226 + ));
227 +
228 + $this->_response = $client;
229 + if (is_wp_error($client)) :
230 + $this->_data = NULL;
231 + $this->_error = $client->get_error_messages();
118 232 else :
233 + $this->_data = $client['body'];
119 234 $this->_error = NULL;
120 235 endif;
121 - $this->_response = $client;
122 - $this->_data = $client->results;
123 236
124 237 // Kilroy was here
125 238 $this->_cache_uri = $this->uri;
126 239 endif;
@@ -125,8 +238,25 @@
125 238 $this->_cache_uri = $this->uri;
126 239 endif;
127 240 } /* FeedFinder::_get () */
128 241
242 + function _opml_rss_uris () {
243 + // Really we should parse the XML and use the structure to
244 + // return something intelligent to programs that want to use it
245 + // Oh babe! maybe some day...
246 +
247 + $opml = $this->data();
248 +
249 + $rx = FeedWordPressHTML::attributeRegex('outline', 'xmlUrl');
250 + if (preg_match_all($rx, $opml, $matches, PREG_SET_ORDER)) :
251 + foreach ($matches as $m) :
252 + $match = FeedWordPressHTML::attributeMatch($m);
253 + $r[] = $match['value'];
254 + endforeach;
255 + endif;
256 + return $r;
257 + } /* FeedFinder::_opml_rss_uris () */
258 +
129 259 function _link_rel_feeds () {
130 260 $links = $this->_tags('link');
131 261 $link_count = count($links);
132 262
@@ -139,9 +269,9 @@
139 269 } /* if */
140 270 } /* if */
141 271 } /* for */
142 272 return $href;
143 - }
273 + } /* FeedFinder::_link_rel_feeds () */
144 274
145 275 function _a_href_feeds ($obvious = TRUE) {
146 276 $pattern = ($obvious ? $this->_obvious_feed_url : $this->_maybe_feed_url);
147 277
@@ -155,10 +285,65 @@
155 285 $href[] = $links[$n]['href'];
156 286 } /* if */
157 287 } /* for */
158 288 return $href;
159 - }
289 + } /* FeedFinder::_link_a_href_feeds () */
160 290
291 + function _url_manipulation_feeds () {
292 + $href = array();
293 +
294 + // check for HTTP GET parameters that look feed-like.
295 + $bits = parse_url($this->uri);
296 + foreach (array('rss', 'rss2', 'atom', 'rdf') as $format) :
297 + if (isset($bits['query']) and (strlen($bits['query']) > 0)) :
298 + $newQuery = preg_replace('/([?&=])(rss2?|atom|rdf)/i', '$1'.$format, $bits['query']);
299 + else :
300 + $newQuery = NULL;
301 + endif;
302 +
303 + if (isset($bits['path']) and (strlen($bits['path']) > 0)) :
304 + $newPath = preg_replace('!([/.])(rss2?|atom|rdf)!i', '$1'.$format, $bits['path']);
305 + else :
306 + $newPath = NULL;
307 + endif;
308 +
309 + // Reassemble, check and return
310 + $credentials = '';
311 + if (isset($bits['user'])) :
312 + $credentials = $bits['user'];
313 + if (isset($bits['pass'])) :
314 + $credentials .= ':'.$bits['pass'];
315 + endif;
316 + $credentials .= '@';
317 + endif;
318 +
319 + // Variations on a theme
320 + $newUrl[0] = (''
321 + .(isset($bits['scheme']) ? $bits['scheme'].':' : '')
322 + .(isset($bits['host']) ? '//'.$credentials.$bits['host'] : '')
323 + .(!is_null($newPath) ? $newPath : '')
324 + .(!is_null($newQuery) ? '?'.$newQuery : '')
325 + .(isset($bits['fragment']) ? '#'.$bits['fragment'] : '')
326 + );
327 + $newUrl[1] = (''
328 + .(isset($bits['scheme']) ? $bits['scheme'].':' : '')
329 + .(isset($bits['host']) ? '//'.$credentials.$bits['host'] : '')
330 + .(!is_null($newPath) ? $newPath : '')
331 + .(isset($bits['query']) ? '?'.$bits['query'] : '')
332 + .(isset($bits['fragment']) ? '#'.$bits['fragment'] : '')
333 + );
334 + $newUrl[2] = (''
335 + .(isset($bits['scheme']) ? $bits['scheme'].':' : '')
336 + .(isset($bits['host']) ? '//'.$credentials.$bits['host'] : '')
337 + .(isset($bits['path']) ? $bits['path'] : '')
338 + .(!is_null($newQuery) ? '?'.$newQuery : '')
339 + .(isset($bits['fragment']) ? '#'.$bits['fragment'] : '')
340 + );
341 + $href = array_merge($href, $newUrl);
342 + endforeach;
343 + return array_unique($href);
344 + } /* FeedFinder::_url_manipulation_feeds () */
345 +
161 346 function _tags ($tag) {
162 347 $html = $this->data();
163 348
164 349 // search through the HTML, save all <link> tags
@@ -178,7 +363,7 @@
178 363 } /* foreach */
179 364 $ret[$n] = $final_link;
180 365 } /* for */
181 366 return $ret;
182 - }
367 + } /* FeedFinder::_tags () */
183 368 } /* class FeedFinder */
184 369