diff --git a/wp-includes/SimplePie/Cache/Redis.php b/wp-includes/SimplePie/Cache/Redis.php index dbc88e829a..a5925bec2f 100644 --- a/wp-includes/SimplePie/Cache/Redis.php +++ b/wp-includes/SimplePie/Cache/Redis.php @@ -152,7 +152,7 @@ class SimplePie_Cache_Redis implements SimplePie_Cache_Base { if ($data !== false) { $return = $this->cache->set($this->name, $data); if ($this->options['expire']) { - return $this->cache->expire($this->name, $this->ttl); + return $this->cache->expire($this->name, $this->options['expire']); } return $return; } diff --git a/wp-includes/SimplePie/Enclosure.php b/wp-includes/SimplePie/Enclosure.php index 32216d848c..8a4cffa30e 100644 --- a/wp-includes/SimplePie/Enclosure.php +++ b/wp-includes/SimplePie/Enclosure.php @@ -1152,7 +1152,12 @@ class SimplePie_Enclosure // If we encounter an unsupported mime-type, check the file extension and guess intelligently. if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3))) { - switch (strtolower($this->get_extension())) + $extension = $this->get_extension(); + if ($extension === null) { + return null; + } + + switch (strtolower($extension)) { // Audio mime-types case 'aac': diff --git a/wp-includes/SimplePie/File.php b/wp-includes/SimplePie/File.php index 90ad8196a6..c2d368b3b8 100644 --- a/wp-includes/SimplePie/File.php +++ b/wp-includes/SimplePie/File.php @@ -106,7 +106,7 @@ class SimplePie_File curl_setopt($fp, CURLOPT_FAILONERROR, 1); curl_setopt($fp, CURLOPT_TIMEOUT, $timeout); curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout); - curl_setopt($fp, CURLOPT_REFERER, $url); + curl_setopt($fp, CURLOPT_REFERER, SimplePie_Misc::url_remove_credentials($url)); curl_setopt($fp, CURLOPT_USERAGENT, $useragent); curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2); foreach ($curl_options as $curl_param => $curl_value) { @@ -119,6 +119,7 @@ class SimplePie_File curl_setopt($fp, CURLOPT_ENCODING, 'none'); $this->headers = curl_exec($fp); } + $this->status_code = curl_getinfo($fp, CURLINFO_HTTP_CODE); if (curl_errno($fp)) { $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp); diff --git a/wp-includes/SimplePie/HTTP/Parser.php b/wp-includes/SimplePie/HTTP/Parser.php index 1dbe06c3e3..a4c48ddb71 100644 --- a/wp-includes/SimplePie/HTTP/Parser.php +++ b/wp-includes/SimplePie/HTTP/Parser.php @@ -507,11 +507,13 @@ class SimplePie_HTTP_Parser { $data = explode("\r\n\r\n", $headers, $count); $data = array_pop($data); - if (false !== stripos($data, "HTTP/1.0 200 Connection established\r\n\r\n")) { - $data = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $data); + if (false !== stripos($data, "HTTP/1.0 200 Connection established\r\n")) { + $exploded = explode("\r\n\r\n", $data, 2); + $data = end($exploded); } - if (false !== stripos($data, "HTTP/1.1 200 Connection established\r\n\r\n")) { - $data = str_ireplace("HTTP/1.1 200 Connection established\r\n\r\n", '', $data); + if (false !== stripos($data, "HTTP/1.1 200 Connection established\r\n")) { + $exploded = explode("\r\n\r\n", $data, 2); + $data = end($exploded); } return $data; } diff --git a/wp-includes/SimplePie/Item.php b/wp-includes/SimplePie/Item.php index 5be6b19940..3ac4fa882b 100644 --- a/wp-includes/SimplePie/Item.php +++ b/wp-includes/SimplePie/Item.php @@ -1803,7 +1803,7 @@ class SimplePie_Item } if (isset($content['attribs']['']['fileSize'])) { - $length = ceil($content['attribs']['']['fileSize']); + $length = intval($content['attribs']['']['fileSize']); } if (isset($content['attribs']['']['medium'])) { @@ -2425,7 +2425,7 @@ class SimplePie_Item } if (isset($content['attribs']['']['fileSize'])) { - $length = ceil($content['attribs']['']['fileSize']); + $length = intval($content['attribs']['']['fileSize']); } if (isset($content['attribs']['']['medium'])) { @@ -2790,7 +2790,7 @@ class SimplePie_Item } if (isset($link['attribs']['']['length'])) { - $length = ceil($link['attribs']['']['length']); + $length = intval($link['attribs']['']['length']); } if (isset($link['attribs']['']['title'])) { @@ -2833,7 +2833,7 @@ class SimplePie_Item } if (isset($link['attribs']['']['length'])) { - $length = ceil($link['attribs']['']['length']); + $length = intval($link['attribs']['']['length']); } // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor @@ -2862,13 +2862,14 @@ class SimplePie_Item $width = null; $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0])); + $url = $this->feed->sanitize->https_url($url); if (isset($enclosure[0]['attribs']['']['type'])) { $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); } if (isset($enclosure[0]['attribs']['']['length'])) { - $length = ceil($enclosure[0]['attribs']['']['length']); + $length = intval($enclosure[0]['attribs']['']['length']); } // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor diff --git a/wp-includes/SimplePie/Locator.php b/wp-includes/SimplePie/Locator.php index a207df6fee..c5fae05791 100644 --- a/wp-includes/SimplePie/Locator.php +++ b/wp-includes/SimplePie/Locator.php @@ -64,6 +64,7 @@ class SimplePie_Locator var $max_checked_feeds = 10; var $force_fsockopen = false; var $curl_options = array(); + var $dom; protected $registry; public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10, $force_fsockopen = false, $curl_options = array()) @@ -75,12 +76,19 @@ class SimplePie_Locator $this->force_fsockopen = $force_fsockopen; $this->curl_options = $curl_options; - if (class_exists('DOMDocument')) + if (class_exists('DOMDocument') && $this->file->body != '') { $this->dom = new DOMDocument(); set_error_handler(array('SimplePie_Misc', 'silence_errors')); - $this->dom->loadHTML($this->file->body); + try + { + $this->dom->loadHTML($this->file->body); + } + catch (Throwable $ex) + { + $this->dom = null; + } restore_error_handler(); } else diff --git a/wp-includes/SimplePie/Misc.php b/wp-includes/SimplePie/Misc.php index a52498ac76..ce3cf0f546 100644 --- a/wp-includes/SimplePie/Misc.php +++ b/wp-includes/SimplePie/Misc.php @@ -2260,4 +2260,14 @@ function embed_wmedia(width, height, link) { { // No-op } + + /** + * Sanitize a URL by removing HTTP credentials. + * @param string $url the URL to sanitize. + * @return string the same URL without HTTP credentials. + */ + public static function url_remove_credentials($url) + { + return preg_replace('#^(https?://)[^/:@]+:[^/:@]+@#i', '$1', $url); + } } diff --git a/wp-includes/SimplePie/Parser.php b/wp-includes/SimplePie/Parser.php index 4efdf41a71..3813b74b27 100644 --- a/wp-includes/SimplePie/Parser.php +++ b/wp-includes/SimplePie/Parser.php @@ -164,12 +164,30 @@ class SimplePie_Parser xml_set_element_handler($xml, 'tag_open', 'tag_close'); // Parse! - if (!xml_parse($xml, $data, true)) + $wrapper = @is_writable(sys_get_temp_dir()) ? 'php://temp' : 'php://memory'; + if (($stream = fopen($wrapper, 'r+')) && + fwrite($stream, $data) && + rewind($stream)) + { + //Parse by chunks not to use too much memory + do + { + $stream_data = fread($stream, 1048576); + if (!xml_parse($xml, $stream_data === false ? '' : $stream_data, feof($stream))) + { + $this->error_code = xml_get_error_code($xml); + $this->error_string = xml_error_string($this->error_code); + $return = false; + break; + } + } while (!feof($stream)); + fclose($stream); + } + else { - $this->error_code = xml_get_error_code($xml); - $this->error_string = xml_error_string($this->error_code); $return = false; } + $this->current_line = xml_get_current_line_number($xml); $this->current_column = xml_get_current_column_number($xml); $this->current_byte = xml_get_current_byte_index($xml); diff --git a/wp-includes/SimplePie/Registry.php b/wp-includes/SimplePie/Registry.php index bf3baf1793..1aac51d07a 100644 --- a/wp-includes/SimplePie/Registry.php +++ b/wp-includes/SimplePie/Registry.php @@ -208,7 +208,8 @@ class SimplePie_Registry { case 'Cache': // For backwards compatibility with old non-static - // Cache::create() methods + // Cache::create() methods in PHP < 8.0. + // No longer supported as of PHP 8.0. if ($method === 'get_handler') { $result = @call_user_func_array(array($class, 'create'), $parameters); diff --git a/wp-includes/SimplePie/Sanitize.php b/wp-includes/SimplePie/Sanitize.php index 35838032fc..d421c83072 100644 --- a/wp-includes/SimplePie/Sanitize.php +++ b/wp-includes/SimplePie/Sanitize.php @@ -71,6 +71,15 @@ class SimplePie_Sanitize var $useragent = ''; var $force_fsockopen = false; var $replace_url_attributes = null; + var $registry; + + /** + * List of domains for which to force HTTPS. + * @see SimplePie_Sanitize::set_https_domains() + * Array is a tree split at DNS levels. Example: + * array('biz' => true, 'com' => array('example' => true), 'net' => array('example' => array('www' => true))) + */ + var $https_domains = array(); public function __construct() { @@ -241,6 +250,68 @@ class SimplePie_Sanitize $this->replace_url_attributes = (array) $element_attribute; } + /** + * Set the list of domains for which to force HTTPS. + * @see SimplePie_Misc::https_url() + * Example array('biz', 'example.com', 'example.org', 'www.example.net'); + */ + public function set_https_domains($domains) + { + $this->https_domains = array(); + foreach ($domains as $domain) + { + $domain = trim($domain, ". \t\n\r\0\x0B"); + $segments = array_reverse(explode('.', $domain)); + $node =& $this->https_domains; + foreach ($segments as $segment) + {//Build a tree + if ($node === true) + { + break; + } + if (!isset($node[$segment])) + { + $node[$segment] = array(); + } + $node =& $node[$segment]; + } + $node = true; + } + } + + /** + * Check if the domain is in the list of forced HTTPS. + */ + protected function is_https_domain($domain) + { + $domain = trim($domain, '. '); + $segments = array_reverse(explode('.', $domain)); + $node =& $this->https_domains; + foreach ($segments as $segment) + {//Explore the tree + if (isset($node[$segment])) + { + $node =& $node[$segment]; + } + else + { + break; + } + } + return $node === true; + } + + /** + * Force HTTPS for selected Web sites. + */ + public function https_url($url) + { + return (strtolower(substr($url, 0, 7)) === 'http://') && + $this->is_https_domain(parse_url($url, PHP_URL_HOST)) ? + substr_replace($url, 's', 4, 0) : //Add the 's' to HTTPS + $url; + } + public function sanitize($data, $type, $base = '') { $data = trim($data); @@ -443,6 +514,7 @@ class SimplePie_Sanitize $value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base)); if ($value !== false) { + $value = $this->https_url($value); $element->setAttribute($attribute, $value); } } diff --git a/wp-includes/class-simplepie.php b/wp-includes/class-simplepie.php index ff55274509..e5f72292a4 100644 --- a/wp-includes/class-simplepie.php +++ b/wp-includes/class-simplepie.php @@ -459,6 +459,13 @@ class SimplePie */ public $error; + /** + * @var int HTTP status code + * @see SimplePie::status_code() + * @access private + */ + public $status_code; + /** * @var object Instance of SimplePie_Sanitize (or other class) * @see SimplePie::set_sanitize_class() @@ -943,6 +950,39 @@ class SimplePie $this->cache_location = (string) $location; } + /** + * Return the filename (i.e. hash, without path and without extension) of the file to cache a given URL. + * @param string $url The URL of the feed to be cached. + * @return string A filename (i.e. hash, without path and without extension). + */ + public function get_cache_filename($url) + { + // Append custom parameters to the URL to avoid cache pollution in case of multiple calls with different parameters. + $url .= $this->force_feed ? '#force_feed' : ''; + $options = array(); + if ($this->timeout != 10) + { + $options[CURLOPT_TIMEOUT] = $this->timeout; + } + if ($this->useragent !== SIMPLEPIE_USERAGENT) + { + $options[CURLOPT_USERAGENT] = $this->useragent; + } + if (!empty($this->curl_options)) + { + foreach ($this->curl_options as $k => $v) + { + $options[$k] = $v; + } + } + if (!empty($options)) + { + ksort($options); + $url .= '#' . urlencode(var_export($options, true)); + } + return call_user_func($this->cache_name_function, $url); + } + /** * Set whether feed items should be sorted into reverse chronological order * @@ -1181,6 +1221,7 @@ class SimplePie $this->strip_attributes(false); $this->add_attributes(false); $this->set_image_handler(false); + $this->set_https_domains(array()); } } @@ -1283,6 +1324,19 @@ class SimplePie $this->sanitize->set_url_replacements($element_attribute); } + /** + * Set the list of domains for which to force HTTPS. + * @see SimplePie_Sanitize::set_https_domains() + * @param array List of HTTPS domains. Example array('biz', 'example.com', 'example.org', 'www.example.net'). + */ + public function set_https_domains($domains = array()) + { + if (is_array($domains)) + { + $this->sanitize->set_https_domains($domains); + } + } + /** * Set the handler to enable the display of cached images. * @@ -1408,8 +1462,8 @@ class SimplePie // Decide whether to enable caching if ($this->cache && $parsed_feed_url['scheme'] !== '') { - $url = $this->feed_url . ($this->force_feed ? '#force_feed' : ''); - $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $url), 'spc')); + $filename = $this->get_cache_filename($this->feed_url); + $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, $filename, 'spc')); } // Fetch the data via SimplePie_File into $this->raw_data @@ -1549,7 +1603,7 @@ class SimplePie * Fetch the data via SimplePie_File * * If the data is already cached, attempt to fetch it from there instead - * @param SimplePie_Cache|false $cache Cache handler, or false to not load from the cache + * @param SimplePie_Cache_Base|false $cache Cache handler, or false to not load from the cache * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type */ protected function fetch_data(&$cache) @@ -1612,6 +1666,7 @@ class SimplePie } $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options)); + $this->status_code = $file->status_code; if ($file->success) { @@ -1666,6 +1721,8 @@ class SimplePie $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options)); } } + $this->status_code = $file->status_code; + // If the file connection has an error, set SimplePie::error to that and quit if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300))) { @@ -1772,6 +1829,16 @@ class SimplePie return $this->error; } + /** + * Get the last HTTP status code + * + * @return int Status code + */ + public function status_code() + { + return $this->status_code; + } + /** * Get the raw XML * @@ -2615,13 +2682,19 @@ class SimplePie } } - if (isset($this->data['headers']['link']) && - preg_match('/<([^>]+)>; rel='.preg_quote($rel).'/', - $this->data['headers']['link'], $match)) + if (isset($this->data['headers']['link'])) { - return array($match[1]); + $link_headers = $this->data['headers']['link']; + if (is_string($link_headers)) { + $link_headers = array($link_headers); + } + $matches = preg_filter('/<([^>]+)>; rel='.preg_quote($rel).'/', '$1', $link_headers); + if (!empty($matches)) { + return $matches; + } } - else if (isset($this->data['links'][$rel])) + + if (isset($this->data['links'][$rel])) { return $this->data['links'][$rel]; } diff --git a/wp-includes/version.php b/wp-includes/version.php index a0cd2aa712..d79bfeeaed 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '5.9-beta3-52392'; +$wp_version = '5.9-beta3-52393'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.