PluginProbe
FeedWordPress / 2017.1004
FeedWordPress v2017.1004
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 +215 -43 2010.05282017.1004 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,130 @@
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 - unset($feed);
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 161 if (!is_wp_error($this->_response) and isset($this->_response['response']['code'])) :
@@ -94,8 +177,12 @@
94 177 endif;
95 178 return $message;
96 179 }
97 180
181 + function is_401 ($uri = NULL) {
182 + return (intval($this->status($uri))==401);
183 + } /* FeedFinder::is_401 () */
184 +
98 185 function is_feed ($uri = NULL) {
99 186 $data = $this->data($uri);
100 187
101 188 return (
@@ -108,22 +195,35 @@
108 195 )
109 196 );
110 197 } /* FeedFinder::is_feed () */
111 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 +
112 209 # --- Private methods ---
113 210 function _get ($uri = NULL) {
114 211 if ($uri) $this->uri = $uri;
115 212
116 213 // Is the result not yet cached?
117 - if ($this->_cache_uri !== $this->uri) :
214 + if ($this->uri != 'tag:localhost' and $this->_cache_uri !== $this->uri) :
118 215 $headers['Connection'] = 'close';
119 216 $headers['Accept'] = 'application/atom+xml application/rdf+xml application/rss+xml application/xml text/html */*';
120 217 $headers['User-Agent'] = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress';
121 218
122 219 // Use WordPress API function
123 - $client = wp_remote_request($this->uri, array(
220 + $client = wp_remote_request($this->uri, array_merge(
221 + $this->credentials,
222 + array(
124 223 'headers' => $headers,
125 - 'timeout' => FEEDWORDPRESS_FETCH_TIME_OUT,
224 + 'timeout' => FeedWordPress::fetch_timeout(),
225 + )
126 226 ));
127 227
128 228 $this->_response = $client;
129 229 if (is_wp_error($client)) :
@@ -138,8 +238,25 @@
138 238 $this->_cache_uri = $this->uri;
139 239 endif;
140 240 } /* FeedFinder::_get () */
141 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 +
142 259 function _link_rel_feeds () {
143 260 $links = $this->_tags('link');
144 261 $link_count = count($links);
145 262
@@ -152,9 +269,9 @@
152 269 } /* if */
153 270 } /* if */
154 271 } /* for */
155 272 return $href;
156 - }
273 + } /* FeedFinder::_link_rel_feeds () */
157 274
158 275 function _a_href_feeds ($obvious = TRUE) {
159 276 $pattern = ($obvious ? $this->_obvious_feed_url : $this->_maybe_feed_url);
160 277
@@ -168,10 +285,65 @@
168 285 $href[] = $links[$n]['href'];
169 286 } /* if */
170 287 } /* for */
171 288 return $href;
172 - }
289 + } /* FeedFinder::_link_a_href_feeds () */
173 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 +
174 346 function _tags ($tag) {
175 347 $html = $this->data();
176 348
177 349 // search through the HTML, save all <link> tags
@@ -191,7 +363,7 @@
191 363 } /* foreach */
192 364 $ret[$n] = $final_link;
193 365 } /* for */
194 366 return $ret;
195 - }
367 + } /* FeedFinder::_tags () */
196 368 } /* class FeedFinder */
197 369