PluginProbe
FeedWordPress / 2011.0512
FeedWordPress v2011.0512
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 +178 -50 2009.06132011.0512 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,61 +31,86 @@
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 - $feed = NULL;
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 - if (isset($this->_response->status)) :
79 - $ret = $this->_response->status;
111 + if (!is_wp_error($this->_response) and isset($this->_response['response']['code'])) :
112 + $ret = $this->_response['response']['code'];
80 113 else :
81 114 $ret = NULL;
82 115 endif;
83 116 return $ret;
@@ -82,10 +115,18 @@
82 115 endif;
83 116 return $ret;
84 117 }
85 118
86 - function error () {
87 - return $this->_error;
119 + function error ($index = NULL) {
120 + $message = NULL;
121 + if (count($this->_error) > 0) :
122 + if (is_scalar($index) and !is_null($index)) :
123 + $message = $this->_error[$index];
124 + else :
125 + $message = implode(" / ", $this->_error)."\n";
126 + endif;
127 + endif;
128 + return $message;
88 129 }
89 130
90 131 function is_feed ($uri = NULL) {
91 132 $data = $this->data($uri);
@@ -100,27 +141,42 @@
100 141 )
101 142 );
102 143 } /* FeedFinder::is_feed () */
103 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 +
104 155 # --- Private methods ---
105 156 function _get ($uri = NULL) {
106 157 if ($uri) $this->uri = $uri;
107 158
108 159 // Is the result not yet cached?
109 - if ($this->_cache_uri !== $this->uri) :
160 + if ($this->uri != 'tag:localhost' and $this->_cache_uri !== $this->uri) :
110 161 $headers['Connection'] = 'close';
111 162 $headers['Accept'] = 'application/atom+xml application/rdf+xml application/rss+xml application/xml text/html */*';
112 163 $headers['User-Agent'] = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress';
113 164
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;
165 + // Use WordPress API function
166 + $client = wp_remote_request($this->uri, array(
167 + 'headers' => $headers,
168 + 'timeout' => FeedWordPress::fetch_timeout(),
169 + ));
170 +
171 + $this->_response = $client;
172 + if (is_wp_error($client)) :
173 + $this->_data = NULL;
174 + $this->_error = $client->get_error_messages();
118 175 else :
176 + $this->_data = $client['body'];
119 177 $this->_error = NULL;
120 178 endif;
121 - $this->_response = $client;
122 - $this->_data = $client->results;
123 179
124 180 // Kilroy was here
125 181 $this->_cache_uri = $this->uri;
126 182 endif;
@@ -125,8 +181,25 @@
125 181 $this->_cache_uri = $this->uri;
126 182 endif;
127 183 } /* FeedFinder::_get () */
128 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 +
129 202 function _link_rel_feeds () {
130 203 $links = $this->_tags('link');
131 204 $link_count = count($links);
132 205
@@ -139,9 +212,9 @@
139 212 } /* if */
140 213 } /* if */
141 214 } /* for */
142 215 return $href;
143 - }
216 + } /* FeedFinder::_link_rel_feeds () */
144 217
145 218 function _a_href_feeds ($obvious = TRUE) {
146 219 $pattern = ($obvious ? $this->_obvious_feed_url : $this->_maybe_feed_url);
147 220
@@ -155,10 +228,65 @@
155 228 $href[] = $links[$n]['href'];
156 229 } /* if */
157 230 } /* for */
158 231 return $href;
159 - }
232 + } /* FeedFinder::_link_a_href_feeds () */
160 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 +
161 289 function _tags ($tag) {
162 290 $html = $this->data();
163 291
164 292 // search through the HTML, save all <link> tags
@@ -178,7 +306,7 @@
178 306 } /* foreach */
179 307 $ret[$n] = $final_link;
180 308 } /* for */
181 309 return $ret;
182 - }
310 + } /* FeedFinder::_tags () */
183 311 } /* class FeedFinder */
184 312