PluginProbe
FeedWordPress / 2011.0211
FeedWordPress v2011.0211
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 +156 -41 2010.05282011.0211 View file →
@@ -1,15 +1,23 @@
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;
8 15 var $_cache_uri = NULL;
9 16
10 17 var $verify = FALSE;
11 -
18 + var $fallbacks = 3;
19 +
12 20 var $_response = NULL;
13 21 var $_data = NULL;
14 22 var $_error = NULL;
15 23 var $_head = NULL;
@@ -23,56 +31,81 @@
23 31 'application/x-atom+xml'
24 32 );
25 33 var $_feed_markers = array('\\<feed', '\\<rss', 'xmlns="http://purl.org/rss/1.0');
26 34 var $_html_markers = array('\\<html');
35 + var $_opml_markers = array('\\<opml', '\\<outline');
27 36 var $_obvious_feed_url = array('[./]rss', '[./]rdf', '[./]atom', '[./]feed', '\.xml');
28 37 var $_maybe_feed_url = array ('rss', 'rdf', 'atom', 'feed', 'xml');
29 38
30 - function FeedFinder ($uri = NULL, $verify = TRUE) {
39 + function FeedFinder ($uri = NULL, $verify = TRUE, $fallbacks = 3) {
31 40 $this->uri = $uri; $this->verify = $verify;
41 + $this->fallbacks = $fallbacks;
32 42 } /* FeedFinder::FeedFinder () */
33 43
34 44 function find ($uri = NULL) {
35 45 $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);
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;
49 73
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);
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);
53 81
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);
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);
68 96 } /* FeedFinder::find () */
69 97
70 98 function data ($uri = NULL) {
71 99 $this->_get($uri);
72 100 return $this->_data;
73 - }
101 + } /* FeedFinder::data () */
74 102
103 + function upload_data ($data) {
104 + $this->uri = 'tag:localhost';
105 + $this->_data = $data;
106 + } /* FeedFinder::upload_data () */
107 +
75 108 function status ($uri = NULL) {
76 109 $this->_get($uri);
77 110
78 111 if (!is_wp_error($this->_response) and isset($this->_response['response']['code'])) :
@@ -108,14 +141,24 @@
108 141 )
109 142 );
110 143 } /* FeedFinder::is_feed () */
111 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 +
112 155 # --- Private methods ---
113 156 function _get ($uri = NULL) {
114 157 if ($uri) $this->uri = $uri;
115 158
116 159 // Is the result not yet cached?
117 - if ($this->_cache_uri !== $this->uri) :
160 + if ($this->uri != 'tag:localhost' and $this->_cache_uri !== $this->uri) :
118 161 $headers['Connection'] = 'close';
119 162 $headers['Accept'] = 'application/atom+xml application/rdf+xml application/rss+xml application/xml text/html */*';
120 163 $headers['User-Agent'] = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress';
121 164
@@ -121,9 +164,9 @@
121 164
122 165 // Use WordPress API function
123 166 $client = wp_remote_request($this->uri, array(
124 167 'headers' => $headers,
125 - 'timeout' => FEEDWORDPRESS_FETCH_TIME_OUT,
168 + 'timeout' => FeedWordPress::fetch_timeout(),
126 169 ));
127 170
128 171 $this->_response = $client;
129 172 if (is_wp_error($client)) :
@@ -138,8 +181,25 @@
138 181 $this->_cache_uri = $this->uri;
139 182 endif;
140 183 } /* FeedFinder::_get () */
141 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 +
142 202 function _link_rel_feeds () {
143 203 $links = $this->_tags('link');
144 204 $link_count = count($links);
145 205
@@ -152,9 +212,9 @@
152 212 } /* if */
153 213 } /* if */
154 214 } /* for */
155 215 return $href;
156 - }
216 + } /* FeedFinder::_link_rel_feeds () */
157 217
158 218 function _a_href_feeds ($obvious = TRUE) {
159 219 $pattern = ($obvious ? $this->_obvious_feed_url : $this->_maybe_feed_url);
160 220
@@ -168,10 +228,65 @@
168 228 $href[] = $links[$n]['href'];
169 229 } /* if */
170 230 } /* for */
171 231 return $href;
172 - }
232 + } /* FeedFinder::_link_a_href_feeds () */
173 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 +
174 289 function _tags ($tag) {
175 290 $html = $this->data();
176 291
177 292 // search through the HTML, save all <link> tags
@@ -191,7 +306,7 @@
191 306 } /* foreach */
192 307 $ret[$n] = $final_link;
193 308 } /* for */
194 309 return $ret;
195 - }
310 + } /* FeedFinder::_tags () */
196 311 } /* class FeedFinder */
197 312