See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]
1 <?php 2 /** 3 * SimplePie 4 * 5 * A PHP-Based RSS and Atom Feed Framework. 6 * Takes the hard work out of managing a complete RSS/Atom solution. 7 * 8 * Copyright (c) 2004-2016, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without modification, are 12 * permitted provided that the following conditions are met: 13 * 14 * * Redistributions of source code must retain the above copyright notice, this list of 15 * conditions and the following disclaimer. 16 * 17 * * Redistributions in binary form must reproduce the above copyright notice, this list 18 * of conditions and the following disclaimer in the documentation and/or other materials 19 * provided with the distribution. 20 * 21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used 22 * to endorse or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 * 35 * @package SimplePie 36 * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue 37 * @author Ryan Parman 38 * @author Sam Sneddon 39 * @author Ryan McCue 40 * @link http://simplepie.org/ SimplePie 41 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 42 */ 43 44 /** 45 * Used for feed auto-discovery 46 * 47 * 48 * This class can be overloaded with {@see SimplePie::set_locator_class()} 49 * 50 * @package SimplePie 51 */ 52 class SimplePie_Locator 53 { 54 var $useragent; 55 var $timeout; 56 var $file; 57 var $local = array(); 58 var $elsewhere = array(); 59 var $cached_entities = array(); 60 var $http_base; 61 var $base; 62 var $base_location = 0; 63 var $checked_feeds = 0; 64 var $max_checked_feeds = 10; 65 var $force_fsockopen = false; 66 var $curl_options = array(); 67 var $dom; 68 protected $registry; 69 70 public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10, $force_fsockopen = false, $curl_options = array()) 71 { 72 $this->file = $file; 73 $this->useragent = $useragent; 74 $this->timeout = $timeout; 75 $this->max_checked_feeds = $max_checked_feeds; 76 $this->force_fsockopen = $force_fsockopen; 77 $this->curl_options = $curl_options; 78 79 if (class_exists('DOMDocument') && $this->file->body != '') 80 { 81 $this->dom = new DOMDocument(); 82 83 set_error_handler(array('SimplePie_Misc', 'silence_errors')); 84 try 85 { 86 $this->dom->loadHTML($this->file->body); 87 } 88 catch (Throwable $ex) 89 { 90 $this->dom = null; 91 } 92 restore_error_handler(); 93 } 94 else 95 { 96 $this->dom = null; 97 } 98 } 99 100 public function set_registry(SimplePie_Registry $registry) 101 { 102 $this->registry = $registry; 103 } 104 105 public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working = null) 106 { 107 if ($this->is_feed($this->file)) 108 { 109 return $this->file; 110 } 111 112 if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) 113 { 114 $sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file)); 115 if ($sniffer->get_type() !== 'text/html') 116 { 117 return null; 118 } 119 } 120 121 if ($type & ~SIMPLEPIE_LOCATOR_NONE) 122 { 123 $this->get_base(); 124 } 125 126 if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery()) 127 { 128 return $working[0]; 129 } 130 131 if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links()) 132 { 133 if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local)) 134 { 135 return $working[0]; 136 } 137 138 if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local)) 139 { 140 return $working[0]; 141 } 142 143 if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere)) 144 { 145 return $working[0]; 146 } 147 148 if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere)) 149 { 150 return $working[0]; 151 } 152 } 153 return null; 154 } 155 156 public function is_feed($file, $check_html = false) 157 { 158 if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) 159 { 160 $sniffer = $this->registry->create('Content_Type_Sniffer', array($file)); 161 $sniffed = $sniffer->get_type(); 162 $mime_types = array('application/rss+xml', 'application/rdf+xml', 163 'text/rdf', 'application/atom+xml', 'text/xml', 164 'application/xml', 'application/x-rss+xml'); 165 if ($check_html) 166 { 167 $mime_types[] = 'text/html'; 168 } 169 170 return in_array($sniffed, $mime_types); 171 } 172 elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL) 173 { 174 return true; 175 } 176 else 177 { 178 return false; 179 } 180 } 181 182 public function get_base() 183 { 184 if ($this->dom === null) 185 { 186 throw new SimplePie_Exception('DOMDocument not found, unable to use locator'); 187 } 188 $this->http_base = $this->file->url; 189 $this->base = $this->http_base; 190 $elements = $this->dom->getElementsByTagName('base'); 191 foreach ($elements as $element) 192 { 193 if ($element->hasAttribute('href')) 194 { 195 $base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base)); 196 if ($base === false) 197 { 198 continue; 199 } 200 $this->base = $base; 201 $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0; 202 break; 203 } 204 } 205 } 206 207 public function autodiscovery() 208 { 209 $done = array(); 210 $feeds = array(); 211 $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds)); 212 $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds)); 213 $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds)); 214 215 if (!empty($feeds)) 216 { 217 return array_values($feeds); 218 } 219 220 return null; 221 } 222 223 protected function search_elements_by_tag($name, &$done, $feeds) 224 { 225 if ($this->dom === null) 226 { 227 throw new SimplePie_Exception('DOMDocument not found, unable to use locator'); 228 } 229 230 $links = $this->dom->getElementsByTagName($name); 231 foreach ($links as $link) 232 { 233 if ($this->checked_feeds === $this->max_checked_feeds) 234 { 235 break; 236 } 237 if ($link->hasAttribute('href') && $link->hasAttribute('rel')) 238 { 239 $rel = array_unique($this->registry->call('Misc', 'space_separated_tokens', array(strtolower($link->getAttribute('rel'))))); 240 $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1; 241 242 if ($this->base_location < $line) 243 { 244 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base)); 245 } 246 else 247 { 248 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base)); 249 } 250 if ($href === false) 251 { 252 continue; 253 } 254 255 if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && $link->hasAttribute('type') && in_array(strtolower($this->registry->call('Misc', 'parse_mime', array($link->getAttribute('type')))), array('text/html', 'application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href])) 256 { 257 $this->checked_feeds++; 258 $headers = array( 259 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', 260 ); 261 $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options)); 262 if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed, true)) 263 { 264 $feeds[$href] = $feed; 265 } 266 } 267 $done[] = $href; 268 } 269 } 270 271 return $feeds; 272 } 273 274 public function get_links() 275 { 276 if ($this->dom === null) 277 { 278 throw new SimplePie_Exception('DOMDocument not found, unable to use locator'); 279 } 280 281 $links = $this->dom->getElementsByTagName('a'); 282 foreach ($links as $link) 283 { 284 if ($link->hasAttribute('href')) 285 { 286 $href = trim($link->getAttribute('href')); 287 $parsed = $this->registry->call('Misc', 'parse_url', array($href)); 288 if ($parsed['scheme'] === '' || preg_match('/^(https?|feed)?$/i', $parsed['scheme'])) 289 { 290 if (method_exists($link, 'getLineNo') && $this->base_location < $link->getLineNo()) 291 { 292 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base)); 293 } 294 else 295 { 296 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base)); 297 } 298 if ($href === false) 299 { 300 continue; 301 } 302 303 $current = $this->registry->call('Misc', 'parse_url', array($this->file->url)); 304 305 if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority']) 306 { 307 $this->local[] = $href; 308 } 309 else 310 { 311 $this->elsewhere[] = $href; 312 } 313 } 314 } 315 } 316 $this->local = array_unique($this->local); 317 $this->elsewhere = array_unique($this->elsewhere); 318 if (!empty($this->local) || !empty($this->elsewhere)) 319 { 320 return true; 321 } 322 return null; 323 } 324 325 public function get_rel_link($rel) 326 { 327 if ($this->dom === null) 328 { 329 throw new SimplePie_Exception('DOMDocument not found, unable to use '. 330 'locator'); 331 } 332 if (!class_exists('DOMXpath')) 333 { 334 throw new SimplePie_Exception('DOMXpath not found, unable to use '. 335 'get_rel_link'); 336 } 337 338 $xpath = new DOMXpath($this->dom); 339 $query = '//a[@rel and @href] | //link[@rel and @href]'; 340 foreach ($xpath->query($query) as $link) 341 { 342 $href = trim($link->getAttribute('href')); 343 $parsed = $this->registry->call('Misc', 'parse_url', array($href)); 344 if ($parsed['scheme'] === '' || 345 preg_match('/^https?$/i', $parsed['scheme'])) 346 { 347 if (method_exists($link, 'getLineNo') && 348 $this->base_location < $link->getLineNo()) 349 { 350 $href = 351 $this->registry->call('Misc', 'absolutize_url', 352 array(trim($link->getAttribute('href')), 353 $this->base)); 354 } 355 else 356 { 357 $href = 358 $this->registry->call('Misc', 'absolutize_url', 359 array(trim($link->getAttribute('href')), 360 $this->http_base)); 361 } 362 if ($href === false) 363 { 364 return null; 365 } 366 $rel_values = explode(' ', strtolower($link->getAttribute('rel'))); 367 if (in_array($rel, $rel_values)) 368 { 369 return $href; 370 } 371 } 372 } 373 return null; 374 } 375 376 public function extension(&$array) 377 { 378 foreach ($array as $key => $value) 379 { 380 if ($this->checked_feeds === $this->max_checked_feeds) 381 { 382 break; 383 } 384 if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml'))) 385 { 386 $this->checked_feeds++; 387 388 $headers = array( 389 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', 390 ); 391 $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options)); 392 if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) 393 { 394 return array($feed); 395 } 396 else 397 { 398 unset($array[$key]); 399 } 400 } 401 } 402 return null; 403 } 404 405 public function body(&$array) 406 { 407 foreach ($array as $key => $value) 408 { 409 if ($this->checked_feeds === $this->max_checked_feeds) 410 { 411 break; 412 } 413 if (preg_match('/(feed|rss|rdf|atom|xml)/i', $value)) 414 { 415 $this->checked_feeds++; 416 $headers = array( 417 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', 418 ); 419 $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent, $this->force_fsockopen, $this->curl_options)); 420 if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) 421 { 422 return array($feed); 423 } 424 else 425 { 426 unset($array[$key]); 427 } 428 } 429 } 430 return null; 431 } 432 } 433 434 class_alias('SimplePie_Locator', 'SimplePie\Locator', false);
title
Description
Body
title
Description
Body
title
Description
Body
title
Body