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