| @@ -1,29 +1,15 @@ | ||
| 1 | 1 | <?php |
| 2 | -/** | |
| 3 | - * class FeedFinder: find likely feeds using autodetection and/or guesswork | |
| 4 | - * @version 2010.0622 | |
| 5 | - * @uses SimplePie_Misc | |
| 6 | - */ | |
| 2 | +################################################################################ | |
| 3 | +## class FeedFinder: find likely feeds using autodetection and/or guesswork #### | |
| 4 | +################################################################################ | |
| 7 | 5 | |
| 8 | -if ( ! class_exists( 'SimplePie' ) ) : | |
| 9 | - require_once ABSPATH . WPINC . '/class-simplepie.php'; | |
| 10 | -endif; | |
| 11 | -require_once dirname( __FILE__ ) . '/feedwordpresshtml.class.php'; | |
| 12 | - | |
| 13 | -/** | |
| 14 | - * FeedFinder attempts to get all possible RSS/Atom feeds from a site. | |
| 15 | - * | |
| 16 | - * @see SimplePie_Misc | |
| 17 | - */ | |
| 18 | 6 | class FeedFinder { |
| 19 | 7 | var $uri = NULL; |
| 20 | - var $credentials = NULL; | |
| 21 | 8 | var $_cache_uri = NULL; |
| 22 | - | |
| 9 | + | |
| 23 | 10 | var $verify = FALSE; |
| 24 | - var $fallbacks = 3; | |
| 25 | - | |
| 11 | + | |
| 26 | 12 | var $_response = NULL; |
| 27 | 13 | var $_data = NULL; |
| 28 | 14 | var $_error = NULL; |
| 29 | 15 | var $_head = NULL; |
| @@ -33,138 +19,64 @@ | ||
| 33 | 19 | 'application/rss+xml', |
| 34 | 20 | 'text/xml', |
| 35 | 21 | 'application/atom+xml', |
| 36 | 22 | 'application/x.atom+xml', |
| 37 | - 'application/x-atom+xml', | |
| 23 | + 'application/x-atom+xml' | |
| 38 | 24 | ); |
| 39 | 25 | var $_feed_markers = array('\\<feed', '\\<rss', 'xmlns="http://purl.org/rss/1.0'); |
| 40 | 26 | var $_html_markers = array('\\<html'); |
| 41 | - var $_opml_markers = array('\\<opml', '\\<outline'); | |
| 42 | 27 | var $_obvious_feed_url = array('[./]rss', '[./]rdf', '[./]atom', '[./]feed', '\.xml'); |
| 43 | 28 | var $_maybe_feed_url = array ('rss', 'rdf', 'atom', 'feed', 'xml'); |
| 44 | 29 | |
| 45 | - function __construct( $uri = NULL, $params = array(), $fallbacks = 3 ) { | |
| 46 | - if (is_bool($params)) : | |
| 47 | - $params = array("verify" => $params); | |
| 48 | - endif; | |
| 49 | - | |
| 50 | - $params = wp_parse_args($params, array( | |
| 51 | - "verify" => true, | |
| 52 | - "authentication" => NULL, | |
| 53 | - "username" => NULL, | |
| 54 | - "password" => NULL, | |
| 55 | - )); | |
| 56 | - $verify = $params['verify']; | |
| 57 | - $this->credentials = array( | |
| 58 | - "authentication" => $params['authentication'], | |
| 59 | - "username" => $params['username'], | |
| 60 | - "password" => $params['password'], | |
| 61 | - ); | |
| 62 | - | |
| 30 | + function FeedFinder ($uri = NULL, $verify = TRUE) { | |
| 63 | 31 | $this->uri = $uri; $this->verify = $verify; |
| 64 | - $this->fallbacks = $fallbacks; | |
| 65 | 32 | } /* FeedFinder::FeedFinder () */ |
| 66 | 33 | |
| 67 | - function FeedFinder( $uri = NULL, $params = array(), $fallbacks = 3 ) { | |
| 68 | - self::__construct( $uri, $params, $fallbacks ); | |
| 69 | - } | |
| 70 | - | |
| 71 | - function find ($uri = NULL, $params = array()) { | |
| 72 | - $params = wp_parse_args($params, array( // Defaults | |
| 73 | - "authentication" => -1, | |
| 74 | - "username" => NULL, | |
| 75 | - "password" => NULL, | |
| 76 | - )); | |
| 77 | - | |
| 78 | - // Equivalents | |
| 79 | - if ($params['authentication']=='-') : | |
| 80 | - $params['authentication'] = NULL; | |
| 81 | - $params['username'] = NULL; | |
| 82 | - $params['password'] = NULL; | |
| 83 | - endif; | |
| 84 | - | |
| 85 | - // Set/reset | |
| 86 | - if ($params['authentication'] != -1) : | |
| 87 | - $this->credentials = array( | |
| 88 | - "authentication" => $params['authentication'], | |
| 89 | - "username" => $params['username'], | |
| 90 | - "password" => $params['password'], | |
| 91 | - ); | |
| 92 | - endif; | |
| 93 | - | |
| 34 | + function find ($uri = NULL) { | |
| 94 | 35 | $ret = array (); |
| 95 | - if ( !is_null($this->data($uri))) : | |
| 96 | - if ($this->is_opml($uri)) : | |
| 97 | - $href = $this->_opml_rss_uris(); | |
| 98 | - else : | |
| 99 | - if ($this->is_feed($uri)) : | |
| 100 | - $href = array($this->uri); | |
| 101 | - else : | |
| 102 | - // Assume that we have HTML or XHTML (even if we don't, who's | |
| 103 | - // it gonna hurt?) Autodiscovery is the preferred method. | |
| 104 | - $href = $this->_link_rel_feeds(); | |
| 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); | |
| 105 | 49 | |
| 106 | - // ... but we'll also take the little orange buttons | |
| 107 | - if ($this->fallbacks > 0) : | |
| 108 | - $href = array_merge($href, $this->_a_href_feeds(TRUE)); | |
| 109 | - endif; | |
| 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); | |
| 110 | 53 | |
| 111 | - // If all that failed, look harder | |
| 112 | - if ($this->fallbacks > 1) : | |
| 113 | - if (count($href) == 0) : | |
| 114 | - $href = $this->_a_href_feeds(FALSE); | |
| 115 | - endif; | |
| 116 | - endif; | |
| 117 | - | |
| 118 | - // Our search may turn up duplicate URIs. We only need to do | |
| 119 | - // any given URI once. Props to Camilo <http://projects.radgeek.com/2008/12/14/feedwordpress-20081214/#comment-20090122160414> | |
| 120 | - $href = array_unique($href); | |
| 121 | - endif; | |
| 122 | - | |
| 123 | - // Try some clever URL little tricks before we go | |
| 124 | - if ($this->fallbacks > 2) : | |
| 125 | - $href = array_merge($href, $this->_url_manipulation_feeds()); | |
| 126 | - endif; | |
| 127 | - endif; | |
| 128 | - | |
| 129 | - $href = array_unique($href); | |
| 130 | - | |
| 131 | - // Verify feeds and resolve relative URIs | |
| 132 | - foreach ($href as $u) : | |
| 133 | - $the_uri = SimplePie_Misc::absolutize_url($u, $this->uri); | |
| 134 | - if ($this->verify and ($u != $this->uri and $the_uri != $this->uri)) : | |
| 135 | - $feed = new FeedFinder($the_uri, $this->credentials); | |
| 136 | - if ($feed->is_feed()) : $ret[] = $the_uri; endif; | |
| 137 | - unset($feed); | |
| 138 | - else : | |
| 139 | - $ret[] = $the_uri; | |
| 140 | - endif; | |
| 141 | - endforeach; | |
| 142 | - endif; | |
| 143 | - | |
| 144 | - if ($this->is_401($uri)) : | |
| 145 | - $ret = array_merge(array( | |
| 146 | - new WP_Error('http_request_failed', '401 Not authorized', array("uri" => $this->uri, "status" => 401)), | |
| 147 | - ), $ret); | |
| 148 | - endif; | |
| 149 | - | |
| 150 | - return array_values($ret); | |
| 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); | |
| 151 | 68 | } /* FeedFinder::find () */ |
| 152 | 69 | |
| 153 | 70 | function data ($uri = NULL) { |
| 154 | 71 | $this->_get($uri); |
| 155 | 72 | return $this->_data; |
| 156 | - } /* FeedFinder::data () */ | |
| 73 | + } | |
| 157 | 74 | |
| 158 | - function upload_data ($data) { | |
| 159 | - $this->uri = 'tag:localhost'; | |
| 160 | - $this->_data = $data; | |
| 161 | - } /* FeedFinder::upload_data () */ | |
| 162 | - | |
| 163 | 75 | function status ($uri = NULL) { |
| 164 | 76 | $this->_get($uri); |
| 165 | - | |
| 166 | - if ( !is_wp_error($this->_response) and isset($this->_response['response']['code'])) : | |
| 77 | + | |
| 78 | + if (!is_wp_error($this->_response) and isset($this->_response['response']['code'])) : | |
| 167 | 79 | $ret = $this->_response['response']['code']; |
| 168 | 80 | else : |
| 169 | 81 | $ret = NULL; |
| 170 | 82 | endif; |
| @@ -181,13 +93,9 @@ | ||
| 181 | 93 | endif; |
| 182 | 94 | endif; |
| 183 | 95 | return $message; |
| 184 | 96 | } |
| 185 | - | |
| 186 | - function is_401 ($uri = NULL) { | |
| 187 | - return (intval($this->status($uri))==401); | |
| 188 | - } /* FeedFinder::is_401 () */ | |
| 189 | - | |
| 97 | + | |
| 190 | 98 | function is_feed ($uri = NULL) { |
| 191 | 99 | $data = $this->data($uri); |
| 192 | 100 | |
| 193 | 101 | return ( |
| @@ -200,35 +108,22 @@ | ||
| 200 | 108 | ) |
| 201 | 109 | ); |
| 202 | 110 | } /* FeedFinder::is_feed () */ |
| 203 | 111 | |
| 204 | - function is_opml ($uri = NULL) { | |
| 205 | - $data = $this->data($uri); | |
| 206 | - return ( | |
| 207 | - preg_match ( | |
| 208 | - "\007(".implode('|',$this->_opml_markers).")\007i", | |
| 209 | - $data | |
| 210 | - ) | |
| 211 | - ); | |
| 212 | - } /* FeedFinder::is_opml () */ | |
| 213 | - | |
| 214 | 112 | # --- Private methods --- |
| 215 | 113 | function _get ($uri = NULL) { |
| 216 | 114 | if ($uri) $this->uri = $uri; |
| 217 | 115 | |
| 218 | 116 | // Is the result not yet cached? |
| 219 | - if ($this->uri != 'tag:localhost' and $this->_cache_uri !== $this->uri) : | |
| 117 | + if ($this->_cache_uri !== $this->uri) : | |
| 220 | 118 | $headers['Connection'] = 'close'; |
| 221 | 119 | $headers['Accept'] = 'application/atom+xml application/rdf+xml application/rss+xml application/xml text/html */*'; |
| 222 | 120 | $headers['User-Agent'] = 'feedfinder/1.2 (compatible; PHP FeedFinder) +http://projects.radgeek.com/feedwordpress'; |
| 223 | 121 | |
| 224 | 122 | // Use WordPress API function |
| 225 | - $client = wp_remote_request($this->uri, array_merge( | |
| 226 | - $this->credentials, | |
| 227 | - array( | |
| 123 | + $client = wp_remote_request($this->uri, array( | |
| 228 | 124 | 'headers' => $headers, |
| 229 | - 'timeout' => FeedWordPress::fetch_timeout(), | |
| 230 | - ) | |
| 125 | + 'timeout' => FEEDWORDPRESS_FETCH_TIME_OUT, | |
| 231 | 126 | )); |
| 232 | 127 | |
| 233 | 128 | $this->_response = $client; |
| 234 | 129 | if (is_wp_error($client)) : |
| @@ -243,25 +138,8 @@ | ||
| 243 | 138 | $this->_cache_uri = $this->uri; |
| 244 | 139 | endif; |
| 245 | 140 | } /* FeedFinder::_get () */ |
| 246 | 141 | |
| 247 | - function _opml_rss_uris () { | |
| 248 | - // Really we should parse the XML and use the structure to | |
| 249 | - // return something intelligent to programs that want to use it | |
| 250 | - // Oh babe! maybe some day... | |
| 251 | - | |
| 252 | - $opml = $this->data(); | |
| 253 | - | |
| 254 | - $rx = FeedWordPressHTML::attributeRegex('outline', 'xmlUrl'); | |
| 255 | - if (preg_match_all($rx, $opml, $matches, PREG_SET_ORDER)) : | |
| 256 | - foreach ($matches as $m) : | |
| 257 | - $match = FeedWordPressHTML::attributeMatch($m); | |
| 258 | - $r[] = $match['value']; | |
| 259 | - endforeach; | |
| 260 | - endif; | |
| 261 | - return $r; | |
| 262 | - } /* FeedFinder::_opml_rss_uris () */ | |
| 263 | - | |
| 264 | 142 | function _link_rel_feeds () { |
| 265 | 143 | $links = $this->_tags('link'); |
| 266 | 144 | $link_count = count($links); |
| 267 | 145 | |
| @@ -274,9 +152,9 @@ | ||
| 274 | 152 | } /* if */ |
| 275 | 153 | } /* if */ |
| 276 | 154 | } /* for */ |
| 277 | 155 | return $href; |
| 278 | - } /* FeedFinder::_link_rel_feeds () */ | |
| 156 | + } | |
| 279 | 157 | |
| 280 | 158 | function _a_href_feeds ($obvious = TRUE) { |
| 281 | 159 | $pattern = ($obvious ? $this->_obvious_feed_url : $this->_maybe_feed_url); |
| 282 | 160 | |
| @@ -290,68 +168,13 @@ | ||
| 290 | 168 | $href[] = $links[$n]['href']; |
| 291 | 169 | } /* if */ |
| 292 | 170 | } /* for */ |
| 293 | 171 | return $href; |
| 294 | - } /* FeedFinder::_link_a_href_feeds () */ | |
| 172 | + } | |
| 295 | 173 | |
| 296 | - function _url_manipulation_feeds () { | |
| 297 | - $href = array(); | |
| 298 | - | |
| 299 | - // check for HTTP GET parameters that look feed-like. | |
| 300 | - $bits = parse_url($this->uri); | |
| 301 | - foreach (array('rss', 'rss2', 'atom', 'rdf') as $format) : | |
| 302 | - if (isset($bits['query']) and (strlen($bits['query']) > 0)) : | |
| 303 | - $newQuery = preg_replace('/([?&=])(rss2?|atom|rdf)/i', '$1'.$format, $bits['query']); | |
| 304 | - else : | |
| 305 | - $newQuery = NULL; | |
| 306 | - endif; | |
| 307 | - | |
| 308 | - if (isset($bits['path']) and (strlen($bits['path']) > 0)) : | |
| 309 | - $newPath = preg_replace('!([/.])(rss2?|atom|rdf)!i', '$1'.$format, $bits['path']); | |
| 310 | - else : | |
| 311 | - $newPath = NULL; | |
| 312 | - endif; | |
| 313 | - | |
| 314 | - // Reassemble, check and return | |
| 315 | - $credentials = ''; | |
| 316 | - if (isset($bits['user'])) : | |
| 317 | - $credentials = $bits['user']; | |
| 318 | - if (isset($bits['pass'])) : | |
| 319 | - $credentials .= ':'.$bits['pass']; | |
| 320 | - endif; | |
| 321 | - $credentials .= '@'; | |
| 322 | - endif; | |
| 323 | - | |
| 324 | - // Variations on a theme | |
| 325 | - $newUrl[0] = ('' | |
| 326 | - .(isset($bits['scheme']) ? $bits['scheme'].':' : '') | |
| 327 | - .(isset($bits['host']) ? '//'.$credentials.$bits['host'] : '') | |
| 328 | - .( !is_null($newPath) ? $newPath : '') | |
| 329 | - .( !is_null($newQuery) ? '?'.$newQuery : '') | |
| 330 | - .(isset($bits['fragment']) ? '#'.$bits['fragment'] : '') | |
| 331 | - ); | |
| 332 | - $newUrl[1] = ('' | |
| 333 | - .(isset($bits['scheme']) ? $bits['scheme'].':' : '') | |
| 334 | - .(isset($bits['host']) ? '//'.$credentials.$bits['host'] : '') | |
| 335 | - .( !is_null($newPath) ? $newPath : '') | |
| 336 | - .(isset($bits['query']) ? '?'.$bits['query'] : '') | |
| 337 | - .(isset($bits['fragment']) ? '#'.$bits['fragment'] : '') | |
| 338 | - ); | |
| 339 | - $newUrl[2] = ('' | |
| 340 | - .(isset($bits['scheme']) ? $bits['scheme'].':' : '') | |
| 341 | - .(isset($bits['host']) ? '//'.$credentials.$bits['host'] : '') | |
| 342 | - .(isset($bits['path']) ? $bits['path'] : '') | |
| 343 | - .( !is_null($newQuery) ? '?'.$newQuery : '') | |
| 344 | - .(isset($bits['fragment']) ? '#'.$bits['fragment'] : '') | |
| 345 | - ); | |
| 346 | - $href = array_merge($href, $newUrl); | |
| 347 | - endforeach; | |
| 348 | - return array_unique($href); | |
| 349 | - } /* FeedFinder::_url_manipulation_feeds () */ | |
| 350 | - | |
| 351 | 174 | function _tags ($tag) { |
| 352 | 175 | $html = $this->data(); |
| 353 | - | |
| 176 | + | |
| 354 | 177 | // search through the HTML, save all <link> tags |
| 355 | 178 | // and store each link's attributes in an associative array |
| 356 | 179 | preg_match_all('/<'.$tag.'\s+(.*?)\s*\/?>/si', $html, $matches); |
| 357 | 180 | $links = $matches[1]; |
| @@ -368,7 +191,7 @@ | ||
| 368 | 191 | } /* foreach */ |
| 369 | 192 | $ret[$n] = $final_link; |
| 370 | 193 | } /* for */ |
| 371 | 194 | return $ret; |
| 372 | - } /* FeedFinder::_tags () */ | |
| 195 | + } | |
| 373 | 196 | } /* class FeedFinder */ |
| 374 | 197 | |