diff options
19 files changed, 199 insertions, 365 deletions
diff --git a/lib/composer.json b/lib/composer.json index 197ed3a2d..0901f62a6 100644 --- a/lib/composer.json +++ b/lib/composer.json @@ -14,7 +14,7 @@ "marienfressinaud/lib_opml": "0.5.1", "phpgt/cssxpath": "v1.3.0", "phpmailer/phpmailer": "6.10.0", - "simplepie/simplepie": "dev-freshrss#2f0417355a702c678c237eac5ffc273863301a80" + "simplepie/simplepie": "dev-freshrss#d80757267ea1fcbe13d1d1e3a73c2e81f23440de" }, "config": { "sort-packages": true, diff --git a/lib/simplepie/simplepie/CHANGELOG.md b/lib/simplepie/simplepie/CHANGELOG.md index 69b3dc9df..ff12d7cfb 100644 --- a/lib/simplepie/simplepie/CHANGELOG.md +++ b/lib/simplepie/simplepie/CHANGELOG.md @@ -24,6 +24,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Deprecated +- The following `SimplePie\Misc` methods are deprecated without replacement: + - `SimplePie\Misc::element_implode()` + - `SimplePie\Misc::parse_str()` + - `SimplePie\Misc::percent_encoding_normalization()` + - `SimplePie\Misc::strip_comments()` + - `SimplePie\Misc::uncomment_rfc822()` + + If you need any of them, consider copying the function to your codebase. (by @jtojnar in [#899](https://github.com/simplepie/simplepie/pull/899)) - The method `SimplePie\SimplePie::set_file()` is deprecated, use `SimplePie\SimplePie::set_http_client()` or `SimplePie\SimplePie::set_raw_data()` instead - The method `SimplePie\Sanitize::pass_file_data()` is deprecated, use `SimplePie\Sanitize::set_http_client()` instead - Passing multiple URLs to `SimplePie\SimplePie::set_feed_url()` is deprecated. You can create separate `SimplePie` instance per feed and then use `SimplePie::merge_items()` to get a single list of items. ([#795](https://github.com/simplepie/simplepie/pull/795)) diff --git a/lib/simplepie/simplepie/phpstan.neon.dist b/lib/simplepie/simplepie/phpstan.neon.dist index 5450a9acb..d922910f9 100644 --- a/lib/simplepie/simplepie/phpstan.neon.dist +++ b/lib/simplepie/simplepie/phpstan.neon.dist @@ -65,3 +65,6 @@ parameters: message: '(^Access to an undefined property XMLReader::\$\w+\.$)' # Only occurs on PHP ≥ 8.2 reportUnmatched: false + +includes: + - utils/PHPStan/extension.neon diff --git a/lib/simplepie/simplepie/src/File.php b/lib/simplepie/simplepie/src/File.php index a6a444f56..dcc4a690d 100644 --- a/lib/simplepie/simplepie/src/File.php +++ b/lib/simplepie/simplepie/src/File.php @@ -324,98 +324,30 @@ class File implements Response return (int) $this->status_code; } - /** - * Retrieves all message header values. - * - * The keys represent the header name as it will be sent over the wire, and - * each value is an array of strings associated with the header. - * - * // Represent the headers as a string - * foreach ($message->get_headers() as $name => $values) { - * echo $name . ': ' . implode(', ', $values); - * } - * - * // Emit headers iteratively: - * foreach ($message->get_headers() as $name => $values) { - * foreach ($values as $value) { - * header(sprintf('%s: %s', $name, $value), false); - * } - * } - * - * @return string[][] Returns an associative array of the message's headers. - * Each key MUST be a header name, and each value MUST be an array of - * strings for that header. - */ public function get_headers(): array { $this->maybe_update_headers(); return $this->parsed_headers; } - /** - * Checks if a header exists by the given case-insensitive name. - * - * @param string $name Case-insensitive header field name. - * @return bool Returns true if any header names match the given header - * name using a case-insensitive string comparison. Returns false if - * no matching header name is found in the message. - */ public function has_header(string $name): bool { $this->maybe_update_headers(); return $this->get_header($name) !== []; } - /** - * Retrieves a message header value by the given case-insensitive name. - * - * This method returns an array of all the header values of the given - * case-insensitive header name. - * - * If the header does not appear in the message, this method MUST return an - * empty array. - * - * @param string $name Case-insensitive header field name. - * @return string[] An array of string values as provided for the given - * header. If the header does not appear in the message, this method MUST - * return an empty array. - */ public function get_header(string $name): array { $this->maybe_update_headers(); return $this->parsed_headers[strtolower($name)] ?? []; } - /** - * Retrieves a comma-separated string of the values for a single header. - * - * This method returns all of the header values of the given - * case-insensitive header name as a string concatenated together using - * a comma. - * - * NOTE: Not all header values may be appropriately represented using - * comma concatenation. For such headers, use getHeader() instead - * and supply your own delimiter when concatenating. - * - * If the header does not appear in the message, this method MUST return - * an empty string. - * - * @param string $name Case-insensitive header field name. - * @return string A string of values as provided for the given header - * concatenated together using a comma. If the header does not appear in - * the message, this method MUST return an empty string. - */ public function get_header_line(string $name): string { $this->maybe_update_headers(); return implode(', ', $this->get_header($name)); } - /** - * get the body as string - * - * @return string - */ public function get_body_content(): string { return (string) $this->body; diff --git a/lib/simplepie/simplepie/src/HTTP/Client.php b/lib/simplepie/simplepie/src/HTTP/Client.php index 0c67650cf..507c1b0f1 100644 --- a/lib/simplepie/simplepie/src/HTTP/Client.php +++ b/lib/simplepie/simplepie/src/HTTP/Client.php @@ -7,8 +7,6 @@ declare(strict_types=1); namespace SimplePie\HTTP; -use SimplePie\Exception\HttpException; - /** * HTTP Client interface * @@ -24,7 +22,7 @@ interface Client * @param Client::METHOD_* $method * @param array<string, string> $headers * - * @throws HttpException if anything goes wrong requesting the data + * @throws ClientException if anything goes wrong requesting the data */ public function request(string $method, string $url, array $headers = []): Response; } diff --git a/lib/simplepie/simplepie/src/Exception/HttpException.php b/lib/simplepie/simplepie/src/HTTP/ClientException.php index 775373aff..d7c005680 100644 --- a/lib/simplepie/simplepie/src/Exception/HttpException.php +++ b/lib/simplepie/simplepie/src/HTTP/ClientException.php @@ -5,13 +5,15 @@ declare(strict_types=1); -namespace SimplePie\Exception; +namespace SimplePie\HTTP; use SimplePie\Exception as SimplePieException; /** - * HTTP exception class + * Client exception class + * + * @internal */ -final class HttpException extends SimplePieException +final class ClientException extends SimplePieException { } diff --git a/lib/simplepie/simplepie/src/HTTP/FileClient.php b/lib/simplepie/simplepie/src/HTTP/FileClient.php index 2b21601c8..2cbae4d3b 100644 --- a/lib/simplepie/simplepie/src/HTTP/FileClient.php +++ b/lib/simplepie/simplepie/src/HTTP/FileClient.php @@ -8,7 +8,6 @@ declare(strict_types=1); namespace SimplePie\HTTP; use InvalidArgumentException; -use SimplePie\Exception\HttpException; use SimplePie\File; use SimplePie\Misc; use SimplePie\Registry; @@ -42,7 +41,7 @@ final class FileClient implements Client * @param Client::METHOD_* $method * @param array<string, string> $headers * - * @throws HttpException if anything goes wrong requesting the data + * @throws ClientException if anything goes wrong requesting the data */ public function request(string $method, string $url, array $headers = []): Response { @@ -66,11 +65,11 @@ final class FileClient implements Client $this->options['curl_options'] ?? [] ]); } catch (Throwable $th) { - throw new HttpException($th->getMessage(), $th->getCode(), $th); + throw new ClientException($th->getMessage(), $th->getCode(), $th); } - if (!$file->success) { - throw new HttpException($file->error, $file->get_status_code()); // FreshRSS https://github.com/simplepie/simplepie/pull/905 + if (!$file->success && $file->get_status_code() === 0) { + throw new ClientException($file->error); } return $file; diff --git a/lib/simplepie/simplepie/src/HTTP/Psr18Client.php b/lib/simplepie/simplepie/src/HTTP/Psr18Client.php index a1100f2de..b920333e4 100644 --- a/lib/simplepie/simplepie/src/HTTP/Psr18Client.php +++ b/lib/simplepie/simplepie/src/HTTP/Psr18Client.php @@ -12,7 +12,6 @@ use Psr\Http\Client\ClientExceptionInterface; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\UriFactoryInterface; -use SimplePie\Exception\HttpException; use Throwable; /** @@ -71,7 +70,7 @@ final class Psr18Client implements Client * @param string $url * @param array<string,string|string[]> $headers * - * @throws HttpException if anything goes wrong requesting the data + * @throws ClientException if anything goes wrong requesting the data */ public function request(string $method, string $url, array $headers = []): Response { @@ -114,7 +113,7 @@ final class Psr18Client implements Client try { $response = $this->httpClient->sendRequest($request); } catch (ClientExceptionInterface $th) { - throw new HttpException($th->getMessage(), $th->getCode(), $th); + throw new ClientException($th->getMessage(), $th->getCode(), $th); } $statusCode = $response->getStatusCode(); @@ -145,17 +144,17 @@ final class Psr18Client implements Client private function requestLocalFile(string $path): Response { if (!is_readable($path)) { - throw new HttpException(sprintf('file "%s" is not readable', $path)); + throw new ClientException(sprintf('file "%s" is not readable', $path)); } try { $raw = file_get_contents($path); } catch (Throwable $th) { - throw new HttpException($th->getMessage(), $th->getCode(), $th); + throw new ClientException($th->getMessage(), $th->getCode(), $th); } if ($raw === false) { - throw new HttpException('file_get_contents() could not read the file', 1); + throw new ClientException('file_get_contents() could not read the file', 1); } return new RawTextResponse($raw, $path); diff --git a/lib/simplepie/simplepie/src/HTTP/Psr7Response.php b/lib/simplepie/simplepie/src/HTTP/Psr7Response.php index 65fe4a083..7a52c8ec6 100644 --- a/lib/simplepie/simplepie/src/HTTP/Psr7Response.php +++ b/lib/simplepie/simplepie/src/HTTP/Psr7Response.php @@ -41,162 +41,41 @@ final class Psr7Response implements Response $this->requested_url = $requested_url; } - /** - * Return the string representation of the permanent URI of the requested resource - * (the first location after a prefix of (only) permanent redirects). - * - * Depending on which components of the URI are present, the resulting - * string is either a full URI or relative reference according to RFC 3986, - * Section 4.1. The method concatenates the various components of the URI, - * using the appropriate delimiters: - * - * - If a scheme is present, it MUST be suffixed by ":". - * - If an authority is present, it MUST be prefixed by "//". - * - The path can be concatenated without delimiters. But there are two - * cases where the path has to be adjusted to make the URI reference - * valid as PHP does not allow to throw an exception in __toString(): - * - If the path is rootless and an authority is present, the path MUST - * be prefixed by "/". - * - If the path is starting with more than one "/" and no authority is - * present, the starting slashes MUST be reduced to one. - * - If a query is present, it MUST be prefixed by "?". - * - If a fragment is present, it MUST be prefixed by "#". - * - * @see http://tools.ietf.org/html/rfc3986#section-4.1 - */ public function get_permanent_uri(): string { return $this->permanent_url; } - /** - * Return the string representation of the final requested URL after following all redirects. - * - * Depending on which components of the URI are present, the resulting - * string is either a full URI or relative reference according to RFC 3986, - * Section 4.1. The method concatenates the various components of the URI, - * using the appropriate delimiters: - * - * - If a scheme is present, it MUST be suffixed by ":". - * - If an authority is present, it MUST be prefixed by "//". - * - The path can be concatenated without delimiters. But there are two - * cases where the path has to be adjusted to make the URI reference - * valid as PHP does not allow to throw an exception in __toString(): - * - If the path is rootless and an authority is present, the path MUST - * be prefixed by "/". - * - If the path is starting with more than one "/" and no authority is - * present, the starting slashes MUST be reduced to one. - * - If a query is present, it MUST be prefixed by "?". - * - If a fragment is present, it MUST be prefixed by "#". - * - * @see http://tools.ietf.org/html/rfc3986#section-4.1 - */ public function get_final_requested_uri(): string { return $this->requested_url; } - /** - * Gets the response status code. - * - * The status code is a 3-digit integer result code of the server's attempt - * to understand and satisfy the request. - * - * @return int Status code. - */ public function get_status_code(): int { return $this->response->getStatusCode(); } - /** - * Retrieves all message header values. - * - * The keys represent the header name as it will be sent over the wire, and - * each value is an array of strings associated with the header. - * - * // Represent the headers as a string - * foreach ($message->get_headers() as $name => $values) { - * echo $name . ': ' . implode(', ', $values); - * } - * - * // Emit headers iteratively: - * foreach ($message->get_headers() as $name => $values) { - * foreach ($values as $value) { - * header(sprintf('%s: %s', $name, $value), false); - * } - * } - * - * @return string[][] Returns an associative array of the message's headers. - * Each key MUST be a header name, and each value MUST be an array of - * strings for that header. - */ public function get_headers(): array { return $this->response->getHeaders(); } - /** - * Checks if a header exists by the given case-insensitive name. - * - * @param string $name Case-insensitive header field name. - * @return bool Returns true if any header names match the given header - * name using a case-insensitive string comparison. Returns false if - * no matching header name is found in the message. - */ public function has_header(string $name): bool { return $this->response->hasHeader($name); } - /** - * Retrieves a message header value by the given case-insensitive name. - * - * This method returns an array of all the header values of the given - * case-insensitive header name. - * - * If the header does not appear in the message, this method MUST return an - * empty array. - * - * @param string $name Case-insensitive header field name. - * @return string[] An array of string values as provided for the given - * header. If the header does not appear in the message, this method MUST - * return an empty array. - */ public function get_header(string $name): array { return $this->response->getHeader($name); } - /** - * Retrieves a comma-separated string of the values for a single header. - * - * This method returns all of the header values of the given - * case-insensitive header name as a string concatenated together using - * a comma. - * - * NOTE: Not all header values may be appropriately represented using - * comma concatenation. For such headers, use getHeader() instead - * and supply your own delimiter when concatenating. - * - * If the header does not appear in the message, this method MUST return - * an empty string. - * - * @param string $name Case-insensitive header field name. - * @return string A string of values as provided for the given header - * concatenated together using a comma. If the header does not appear in - * the message, this method MUST return an empty string. - */ public function get_header_line(string $name): string { return $this->response->getHeaderLine($name); } - /** - * get the body as string - * - * @return string - */ public function get_body_content(): string { return $this->response->getBody()->__toString(); diff --git a/lib/simplepie/simplepie/src/HTTP/RawTextResponse.php b/lib/simplepie/simplepie/src/HTTP/RawTextResponse.php index 41cb88abc..1cb8fd46d 100644 --- a/lib/simplepie/simplepie/src/HTTP/RawTextResponse.php +++ b/lib/simplepie/simplepie/src/HTTP/RawTextResponse.php @@ -39,162 +39,41 @@ final class RawTextResponse implements Response $this->requested_url = $filepath; } - /** - * Return the string representation of the permanent URI of the requested resource - * (the first location after a prefix of (only) permanent redirects). - * - * Depending on which components of the URI are present, the resulting - * string is either a full URI or relative reference according to RFC 3986, - * Section 4.1. The method concatenates the various components of the URI, - * using the appropriate delimiters: - * - * - If a scheme is present, it MUST be suffixed by ":". - * - If an authority is present, it MUST be prefixed by "//". - * - The path can be concatenated without delimiters. But there are two - * cases where the path has to be adjusted to make the URI reference - * valid as PHP does not allow to throw an exception in __toString(): - * - If the path is rootless and an authority is present, the path MUST - * be prefixed by "/". - * - If the path is starting with more than one "/" and no authority is - * present, the starting slashes MUST be reduced to one. - * - If a query is present, it MUST be prefixed by "?". - * - If a fragment is present, it MUST be prefixed by "#". - * - * @see http://tools.ietf.org/html/rfc3986#section-4.1 - */ public function get_permanent_uri(): string { return $this->permanent_url; } - /** - * Return the string representation of the final requested URL after following all redirects. - * - * Depending on which components of the URI are present, the resulting - * string is either a full URI or relative reference according to RFC 3986, - * Section 4.1. The method concatenates the various components of the URI, - * using the appropriate delimiters: - * - * - If a scheme is present, it MUST be suffixed by ":". - * - If an authority is present, it MUST be prefixed by "//". - * - The path can be concatenated without delimiters. But there are two - * cases where the path has to be adjusted to make the URI reference - * valid as PHP does not allow to throw an exception in __toString(): - * - If the path is rootless and an authority is present, the path MUST - * be prefixed by "/". - * - If the path is starting with more than one "/" and no authority is - * present, the starting slashes MUST be reduced to one. - * - If a query is present, it MUST be prefixed by "?". - * - If a fragment is present, it MUST be prefixed by "#". - * - * @see http://tools.ietf.org/html/rfc3986#section-4.1 - */ public function get_final_requested_uri(): string { return $this->requested_url; } - /** - * Gets the response status code. - * - * The status code is a 3-digit integer result code of the server's attempt - * to understand and satisfy the request. - * - * @return int Status code. - */ public function get_status_code(): int { return 200; } - /** - * Retrieves all message header values. - * - * The keys represent the header name as it will be sent over the wire, and - * each value is an array of strings associated with the header. - * - * // Represent the headers as a string - * foreach ($message->get_headers() as $name => $values) { - * echo $name . ': ' . implode(', ', $values); - * } - * - * // Emit headers iteratively: - * foreach ($message->get_headers() as $name => $values) { - * foreach ($values as $value) { - * header(sprintf('%s: %s', $name, $value), false); - * } - * } - * - * @return string[][] Returns an associative array of the message's headers. - * Each key MUST be a header name, and each value MUST be an array of - * strings for that header. - */ public function get_headers(): array { return []; } - /** - * Checks if a header exists by the given case-insensitive name. - * - * @param string $name Case-insensitive header field name. - * @return bool Returns true if any header names match the given header - * name using a case-insensitive string comparison. Returns false if - * no matching header name is found in the message. - */ public function has_header(string $name): bool { return false; } - /** - * Retrieves a message header value by the given case-insensitive name. - * - * This method returns an array of all the header values of the given - * case-insensitive header name. - * - * If the header does not appear in the message, this method MUST return an - * empty array. - * - * @param string $name Case-insensitive header field name. - * @return string[] An array of string values as provided for the given - * header. If the header does not appear in the message, this method MUST - * return an empty array. - */ public function get_header(string $name): array { return []; } - /** - * Retrieves a comma-separated string of the values for a single header. - * - * This method returns all of the header values of the given - * case-insensitive header name as a string concatenated together using - * a comma. - * - * NOTE: Not all header values may be appropriately represented using - * comma concatenation. For such headers, use getHeader() instead - * and supply your own delimiter when concatenating. - * - * If the header does not appear in the message, this method MUST return - * an empty string. - * - * @param string $name Case-insensitive header field name. - * @return string A string of values as provided for the given header - * concatenated together using a comma. If the header does not appear in - * the message, this method MUST return an empty string. - */ public function get_header_line(string $name): string { return ''; } - /** - * get the body as string - * - * @return string - */ public function get_body_content(): string { return $this->raw_text; diff --git a/lib/simplepie/simplepie/src/Item.php b/lib/simplepie/simplepie/src/Item.php index 8780a83ce..2b0201d77 100644 --- a/lib/simplepie/simplepie/src/Item.php +++ b/lib/simplepie/simplepie/src/Item.php @@ -127,7 +127,7 @@ class Item implements RegistryAware * @param array<string, mixed> $element * @see get_base */ - protected function get_own_base(array $element = []): string + private function get_own_base(array $element = []): string { if (!empty($element['xml_base_explicit']) && isset($element['xml_base'])) { return $element['xml_base']; @@ -1221,11 +1221,11 @@ class Item implements RegistryAware // PLAYER if ($player_parent = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'player')) { if (isset($player_parent[0]['attribs']['']['url'])) { - $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($player_parent[0])); + $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($player_parent[0])); } } elseif ($player_parent = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'player')) { if (isset($player_parent[0]['attribs']['']['url'])) { - $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($player_parent[0])); + $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($player_parent[0])); } } @@ -1345,13 +1345,13 @@ class Item implements RegistryAware if ($thumbnails = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'thumbnail')) { foreach ($thumbnails as $thumbnail) { if (isset($thumbnail['attribs']['']['url'])) { - $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($thumbnail)); + $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($thumbnail)); } } } elseif ($thumbnails = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'thumbnail')) { foreach ($thumbnails as $thumbnail) { if (isset($thumbnail['attribs']['']['url'])) { - $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($thumbnail)); + $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($thumbnail)); } } } @@ -1475,7 +1475,7 @@ class Item implements RegistryAware if (isset($content['attribs']['']['width'])) { $width = $this->sanitize($content['attribs']['']['width'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } - $url = $this->sanitize($content['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($content)); + $url = $this->sanitize($content['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($content)); // Checking the other optional media: elements. Priority: media:content, media:group, item, channel @@ -1734,9 +1734,11 @@ class Item implements RegistryAware // PLAYER if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'])) { - $player = $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'])); + $playerElem = $content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'][0]; + $player = $this->sanitize($playerElem['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($playerElem)); } elseif (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'])) { - $player = $this->sanitize($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'])); + $playerElem = $group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'][0]; + $player = $this->sanitize($playerElem['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($playerElem)); } else { $player = $player_parent; } @@ -1826,14 +1828,14 @@ class Item implements RegistryAware // THUMBNAILS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['thumbnail'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) { - $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($thumbnail)); + $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($thumbnail)); } if (is_array($thumbnails)) { $thumbnails = array_values(array_unique($thumbnails)); } } elseif (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['thumbnail'])) { foreach ($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) { - $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($thumbnail)); + $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($thumbnail)); } if (is_array($thumbnails)) { $thumbnails = array_values(array_unique($thumbnails)); @@ -1931,7 +1933,7 @@ class Item implements RegistryAware $width = $this->sanitize($content['attribs']['']['width'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['url'])) { - $url = $this->sanitize($content['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($content)); + $url = $this->sanitize($content['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($content)); } // Checking the other optional media: elements. Priority: media:content, media:group, item, channel @@ -2086,7 +2088,8 @@ class Item implements RegistryAware // PLAYER if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'])) { if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'])) { - $player = $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'][0])); + $playerElem = $content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'][0]; + $player = $this->sanitize($playerElem['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($playerElem)); } } else { $player = $player_parent; @@ -2142,7 +2145,7 @@ class Item implements RegistryAware if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['thumbnail'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) { if (isset($thumbnail['attribs']['']['url'])) { - $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($thumbnail)); + $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($thumbnail)); } } if (is_array($thumbnails)) { @@ -2182,7 +2185,7 @@ class Item implements RegistryAware $url = null; $width = null; - $url = $this->sanitize($link['attribs']['']['href'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($link)); + $url = $this->sanitize($link['attribs']['']['href'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($link)); if (isset($link['attribs']['']['type'])) { $type = $this->sanitize($link['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } @@ -2218,7 +2221,7 @@ class Item implements RegistryAware $url = null; $width = null; - $url = $this->sanitize($link['attribs']['']['href'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($link)); + $url = $this->sanitize($link['attribs']['']['href'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($link)); if (isset($link['attribs']['']['type'])) { $type = $this->sanitize($link['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } @@ -2249,7 +2252,7 @@ class Item implements RegistryAware $url = null; $width = null; - $url = $this->sanitize($enclosure['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($enclosure)); + $url = $this->sanitize($enclosure['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_own_base($enclosure)); $url = $this->get_sanitize()->https_url($url); if (isset($enclosure['attribs']['']['type'])) { $type = $this->sanitize($enclosure['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); diff --git a/lib/simplepie/simplepie/src/Locator.php b/lib/simplepie/simplepie/src/Locator.php index 79ce5d761..2f06c3f99 100644 --- a/lib/simplepie/simplepie/src/Locator.php +++ b/lib/simplepie/simplepie/src/Locator.php @@ -11,8 +11,8 @@ use DomDocument; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\UriFactoryInterface; -use SimplePie\Exception\HttpException; use SimplePie\HTTP\Client; +use SimplePie\HTTP\ClientException; use SimplePie\HTTP\FileClient; use SimplePie\HTTP\Psr18Client; use SimplePie\HTTP\Response; @@ -263,7 +263,7 @@ class Locator implements RegistryAware if ((!Misc::is_remote_uri($feed->get_final_requested_uri()) || ($feed->get_status_code() === 200 || $feed->get_status_code() > 206 && $feed->get_status_code() < 300)) && $this->is_feed($feed, true)) { $feeds[$href] = $feed; } - } catch (HttpException $th) { + } catch (ClientException $th) { // Just mark it as done and continue. } } @@ -388,7 +388,7 @@ class Locator implements RegistryAware if ((!Misc::is_remote_uri($feed->get_final_requested_uri()) || ($feed->get_status_code() === 200 || $feed->get_status_code() > 206 && $feed->get_status_code() < 300)) && $this->is_feed($feed)) { return [$feed]; } - } catch (HttpException $th) { + } catch (ClientException $th) { // Just unset and continue. } @@ -420,7 +420,7 @@ class Locator implements RegistryAware if ((!Misc::is_remote_uri($feed->get_final_requested_uri()) || ($feed->get_status_code() === 200 || $feed->get_status_code() > 206 && $feed->get_status_code() < 300)) && $this->is_feed($feed)) { return [$feed]; } - } catch (HttpException $th) { + } catch (ClientException $th) { // Just unset and continue. } diff --git a/lib/simplepie/simplepie/src/Misc.php b/lib/simplepie/simplepie/src/Misc.php index b5569510a..2376a8dcc 100644 --- a/lib/simplepie/simplepie/src/Misc.php +++ b/lib/simplepie/simplepie/src/Misc.php @@ -105,11 +105,14 @@ class Misc } /** + * @deprecated since SimplePie 1.9.0. If you need it, you can copy the function to your codebase. But you should consider using `DOMDocument` for any DOM wrangling. * @param array{tag: string, self_closing: bool, attribs: array<string, array{data: string}>, content: string} $element * @return string */ public static function element_implode(array $element) { + // trigger_error(sprintf('Using method "' . __METHOD__ . '" is deprecated since SimplePie 1.9.'), \E_USER_DEPRECATED); + $full = "<{$element['tag']}"; foreach ($element['attribs'] as $key => $value) { $key = strtolower($key); @@ -250,6 +253,7 @@ class Misc } /** + * @deprecated since SimplePie 1.9.0. This functionality is part of `IRI` – if you need it standalone, consider copying the function to your codebase. * @param array<int, string> $match * @return string */ @@ -1712,11 +1716,14 @@ class Misc /** * Strip HTML comments * + * @deprecated since SimplePie 1.9.0. If you need it, you can copy the function to your codebase. But you should consider using `DOMDocument` for any DOM wrangling. * @param string $data Data to strip comments from * @return string Comment stripped string */ public static function strip_comments(string $data) { + // trigger_error(sprintf('Using method "' . __METHOD__ . '" is deprecated since SimplePie 1.9.'), \E_USER_DEPRECATED); + $output = ''; while (($start = strpos($data, '<!--')) !== false) { $output .= substr($data, 0, $start); @@ -1756,11 +1763,14 @@ class Misc /** * Remove RFC822 comments * + * @deprecated since SimplePie 1.9.0. If you need it, consider copying the function to your codebase. * @param string $string Data to strip comments from * @return string Comment stripped string */ public static function uncomment_rfc822(string $string) { + // trigger_error(sprintf('Using method "' . __METHOD__ . '" is deprecated since SimplePie 1.9.'), \E_USER_DEPRECATED); + $position = 0; $length = strlen($string); $depth = 0; @@ -1848,7 +1858,7 @@ class Misc /** * @param array<string, array<string, string>> $attribs - * @return int + * @return int-mask-of<SimplePie::CONSTRUCT_*> */ public static function atom_10_construct_type(array $attribs) { @@ -1872,7 +1882,7 @@ class Misc /** * @param array<string, array<string, string>> $attribs - * @return int + * @return int-mask-of<SimplePie::CONSTRUCT_*> */ public static function atom_10_content_construct_type(array $attribs) { @@ -1964,12 +1974,15 @@ class Misc * Returns an associative array of name/value pairs, where the value is an * array of values that have used the same name * + * @deprecated since SimplePie 1.9.0. If you need it, consider copying the function to your codebase. * @static * @param string $str The input string. * @return array<string, array<string|null>> */ public static function parse_str(string $str) { + // trigger_error(sprintf('Using method "' . __METHOD__ . '" is deprecated since SimplePie 1.9.'), \E_USER_DEPRECATED); + $return = []; $str = explode('&', $str); diff --git a/lib/simplepie/simplepie/src/Parser.php b/lib/simplepie/simplepie/src/Parser.php index 5c748477e..eb171d9dd 100644 --- a/lib/simplepie/simplepie/src/Parser.php +++ b/lib/simplepie/simplepie/src/Parser.php @@ -111,18 +111,14 @@ class Parser implements RegistryAware $declaration = $this->registry->create(DeclarationParser::class, [substr($data, 5, $pos - 5)]); if ($declaration->parse()) { $data = substr($data, $pos + 2); - $data = preg_replace('/^\\s*<!DOCTYPE\\s[^>\\[\\]]*>\s*/', '', $data); // Strip DOCTYPE except if containing an [internal subset] $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . "\n" . - (preg_match('/^\\s*<!DOCTYPE\\s/', $data) ? '' : $this->declare_html_entities()) . // Declare HTML entities only if no remaining DOCTYPE - $data; + self::set_doctype($data); } else { $this->error_string = 'SimplePie bug! Please report this!'; return false; } } else { - $data = preg_replace('/^\\s*<!DOCTYPE\\s[^>\\[\\]]*>\s*/', '', $data); // Strip DOCTYPE except if containing an [internal subset] - $data = (preg_match('/^\\s*<!DOCTYPE\\s/', $data) ? '' : $this->declare_html_entities()) . // Declare HTML entities only if no remaining DOCTYPE - $data; + $data = self::set_doctype($data); } $return = true; @@ -651,11 +647,20 @@ class Parser implements RegistryAware return true; } - private function declare_html_entities(): string + private static function set_doctype(string $data): string + { + // Strip DOCTYPE except if containing an [internal subset] + $data = preg_replace('/^\\s*<!DOCTYPE\\s[^>\\[\\]]*>\s*/', '', $data); + // Declare HTML entities only if no remaining DOCTYPE + $doctype = preg_match('/^\\s*<!DOCTYPE\\s/', $data) ? '' : self::declare_html_entities(); + return $doctype . $data; + } + + private static function declare_html_entities(): string { // This is required because the RSS specification says that entity-encoded // html is allowed, but the xml specification says they must be declared. - return '<!DOCTYPE html [ <!ENTITY nbsp " "> <!ENTITY iexcl "¡"> <!ENTITY cent "¢"> <!ENTITY pound "£"> <!ENTITY curren "¤"> <!ENTITY yen "¥"> <!ENTITY brvbar "¦"> <!ENTITY sect "§"> <!ENTITY uml "¨"> <!ENTITY copy "©"> <!ENTITY ordf "ª"> <!ENTITY laquo "«"> <!ENTITY not "¬"> <!ENTITY shy "­"> <!ENTITY reg "®"> <!ENTITY macr "¯"> <!ENTITY deg "°"> <!ENTITY plusmn "±"> <!ENTITY sup2 "²"> <!ENTITY sup3 "³"> <!ENTITY acute "´"> <!ENTITY micro "µ"> <!ENTITY para "¶"> <!ENTITY middot "·"> <!ENTITY cedil "¸"> <!ENTITY sup1 "¹"> <!ENTITY ordm "º"> <!ENTITY raquo "»"> <!ENTITY frac14 "¼"> <!ENTITY frac12 "½"> <!ENTITY frac34 "¾"> <!ENTITY iquest "¿"> <!ENTITY Agrave "À"> <!ENTITY Aacute "Á"> <!ENTITY Acirc "Â"> <!ENTITY Atilde "Ã"> <!ENTITY Auml "Ä"> <!ENTITY Aring "Å"> <!ENTITY AElig "Æ"> <!ENTITY Ccedil "Ç"> <!ENTITY Egrave "È"> <!ENTITY Eacute "É"> <!ENTITY Ecirc "Ê"> <!ENTITY Euml "Ë"> <!ENTITY Igrave "Ì"> <!ENTITY Iacute "Í"> <!ENTITY Icirc "Î"> <!ENTITY Iuml "Ï"> <!ENTITY ETH "Ð"> <!ENTITY Ntilde "Ñ"> <!ENTITY Ograve "Ò"> <!ENTITY Oacute "Ó"> <!ENTITY Ocirc "Ô"> <!ENTITY Otilde "Õ"> <!ENTITY Ouml "Ö"> <!ENTITY times "×"> <!ENTITY Oslash "Ø"> <!ENTITY Ugrave "Ù"> <!ENTITY Uacute "Ú"> <!ENTITY Ucirc "Û"> <!ENTITY Uuml "Ü"> <!ENTITY Yacute "Ý"> <!ENTITY THORN "Þ"> <!ENTITY szlig "ß"> <!ENTITY agrave "à"> <!ENTITY aacute "á"> <!ENTITY acirc "â"> <!ENTITY atilde "ã"> <!ENTITY auml "ä"> <!ENTITY aring "å"> <!ENTITY aelig "æ"> <!ENTITY ccedil "ç"> <!ENTITY egrave "è"> <!ENTITY eacute "é"> <!ENTITY ecirc "ê"> <!ENTITY euml "ë"> <!ENTITY igrave "ì"> <!ENTITY iacute "í"> <!ENTITY icirc "î"> <!ENTITY iuml "ï"> <!ENTITY eth "ð"> <!ENTITY ntilde "ñ"> <!ENTITY ograve "ò"> <!ENTITY oacute "ó"> <!ENTITY ocirc "ô"> <!ENTITY otilde "õ"> <!ENTITY ouml "ö"> <!ENTITY divide "÷"> <!ENTITY oslash "ø"> <!ENTITY ugrave "ù"> <!ENTITY uacute "ú"> <!ENTITY ucirc "û"> <!ENTITY uuml "ü"> <!ENTITY yacute "ý"> <!ENTITY thorn "þ"> <!ENTITY yuml "ÿ"> <!ENTITY OElig "Œ"> <!ENTITY oelig "œ"> <!ENTITY Scaron "Š"> <!ENTITY scaron "š"> <!ENTITY Yuml "Ÿ"> <!ENTITY fnof "ƒ"> <!ENTITY circ "ˆ"> <!ENTITY tilde "˜"> <!ENTITY Alpha "Α"> <!ENTITY Beta "Β"> <!ENTITY Gamma "Γ"> <!ENTITY Epsilon "Ε"> <!ENTITY Zeta "Ζ"> <!ENTITY Eta "Η"> <!ENTITY Theta "Θ"> <!ENTITY Iota "Ι"> <!ENTITY Kappa "Κ"> <!ENTITY Lambda "Λ"> <!ENTITY Mu "Μ"> <!ENTITY Nu "Ν"> <!ENTITY Xi "Ξ"> <!ENTITY Omicron "Ο"> <!ENTITY Pi "Π"> <!ENTITY Rho "Ρ"> <!ENTITY Sigma "Σ"> <!ENTITY Tau "Τ"> <!ENTITY Upsilon "Υ"> <!ENTITY Phi "Φ"> <!ENTITY Chi "Χ"> <!ENTITY Psi "Ψ"> <!ENTITY Omega "Ω"> <!ENTITY alpha "α"> <!ENTITY beta "β"> <!ENTITY gamma "γ"> <!ENTITY delta "δ"> <!ENTITY epsilon "ε"> <!ENTITY zeta "ζ"> <!ENTITY eta "η"> <!ENTITY theta "θ"> <!ENTITY iota "ι"> <!ENTITY kappa "κ"> <!ENTITY lambda "λ"> <!ENTITY mu "μ"> <!ENTITY nu "ν"> <!ENTITY xi "ξ"> <!ENTITY omicron "ο"> <!ENTITY pi "π"> <!ENTITY rho "ρ"> <!ENTITY sigmaf "ς"> <!ENTITY sigma "σ"> <!ENTITY tau "τ"> <!ENTITY upsilon "υ"> <!ENTITY phi "φ"> <!ENTITY chi "χ"> <!ENTITY psi "ψ"> <!ENTITY omega "ω"> <!ENTITY thetasym "ϑ"> <!ENTITY upsih "ϒ"> <!ENTITY piv "ϖ"> <!ENTITY ensp " "> <!ENTITY emsp " "> <!ENTITY thinsp " "> <!ENTITY zwnj "‌"> <!ENTITY zwj "‍"> <!ENTITY lrm "‎"> <!ENTITY rlm "‏"> <!ENTITY ndash "–"> <!ENTITY mdash "—"> <!ENTITY lsquo "‘"> <!ENTITY rsquo "’"> <!ENTITY sbquo "‚"> <!ENTITY ldquo "“"> <!ENTITY rdquo "”"> <!ENTITY bdquo "„"> <!ENTITY dagger "†"> <!ENTITY Dagger "‡"> <!ENTITY bull "•"> <!ENTITY hellip "…"> <!ENTITY permil "‰"> <!ENTITY prime "′"> <!ENTITY Prime "″"> <!ENTITY lsaquo "‹"> <!ENTITY rsaquo "›"> <!ENTITY oline "‾"> <!ENTITY frasl "⁄"> <!ENTITY euro "€"> <!ENTITY image "ℑ"> <!ENTITY weierp "℘"> <!ENTITY real "ℜ"> <!ENTITY trade "™"> <!ENTITY alefsym "ℵ"> <!ENTITY larr "←"> <!ENTITY uarr "↑"> <!ENTITY rarr "→"> <!ENTITY darr "↓"> <!ENTITY harr "↔"> <!ENTITY crarr "↵"> <!ENTITY lArr "⇐"> <!ENTITY uArr "⇑"> <!ENTITY rArr "⇒"> <!ENTITY dArr "⇓"> <!ENTITY hArr "⇔"> <!ENTITY forall "∀"> <!ENTITY part "∂"> <!ENTITY exist "∃"> <!ENTITY empty "∅"> <!ENTITY nabla "∇"> <!ENTITY isin "∈"> <!ENTITY notin "∉"> <!ENTITY ni "∋"> <!ENTITY prod "∏"> <!ENTITY sum "∑"> <!ENTITY minus "−"> <!ENTITY lowast "∗"> <!ENTITY radic "√"> <!ENTITY prop "∝"> <!ENTITY infin "∞"> <!ENTITY ang "∠"> <!ENTITY and "∧"> <!ENTITY or "∨"> <!ENTITY cap "∩"> <!ENTITY cup "∪"> <!ENTITY int "∫"> <!ENTITY there4 "∴"> <!ENTITY sim "∼"> <!ENTITY cong "≅"> <!ENTITY asymp "≈"> <!ENTITY ne "≠"> <!ENTITY equiv "≡"> <!ENTITY le "≤"> <!ENTITY ge "≥"> <!ENTITY sub "⊂"> <!ENTITY sup "⊃"> <!ENTITY nsub "⊄"> <!ENTITY sube "⊆"> <!ENTITY supe "⊇"> <!ENTITY oplus "⊕"> <!ENTITY otimes "⊗"> <!ENTITY perp "⊥"> <!ENTITY sdot "⋅"> <!ENTITY lceil "⌈"> <!ENTITY rceil "⌉"> <!ENTITY lfloor "⌊"> <!ENTITY rfloor "⌋"> <!ENTITY lang "〈"> <!ENTITY rang "〉"> <!ENTITY loz "◊"> <!ENTITY spades "♠"> <!ENTITY clubs "♣"> <!ENTITY hearts "♥"> <!ENTITY diams "♦"> ]>'; + return '<!DOCTYPE rss [ <!ENTITY nbsp " "> <!ENTITY iexcl "¡"> <!ENTITY cent "¢"> <!ENTITY pound "£"> <!ENTITY curren "¤"> <!ENTITY yen "¥"> <!ENTITY brvbar "¦"> <!ENTITY sect "§"> <!ENTITY uml "¨"> <!ENTITY copy "©"> <!ENTITY ordf "ª"> <!ENTITY laquo "«"> <!ENTITY not "¬"> <!ENTITY shy "­"> <!ENTITY reg "®"> <!ENTITY macr "¯"> <!ENTITY deg "°"> <!ENTITY plusmn "±"> <!ENTITY sup2 "²"> <!ENTITY sup3 "³"> <!ENTITY acute "´"> <!ENTITY micro "µ"> <!ENTITY para "¶"> <!ENTITY middot "·"> <!ENTITY cedil "¸"> <!ENTITY sup1 "¹"> <!ENTITY ordm "º"> <!ENTITY raquo "»"> <!ENTITY frac14 "¼"> <!ENTITY frac12 "½"> <!ENTITY frac34 "¾"> <!ENTITY iquest "¿"> <!ENTITY Agrave "À"> <!ENTITY Aacute "Á"> <!ENTITY Acirc "Â"> <!ENTITY Atilde "Ã"> <!ENTITY Auml "Ä"> <!ENTITY Aring "Å"> <!ENTITY AElig "Æ"> <!ENTITY Ccedil "Ç"> <!ENTITY Egrave "È"> <!ENTITY Eacute "É"> <!ENTITY Ecirc "Ê"> <!ENTITY Euml "Ë"> <!ENTITY Igrave "Ì"> <!ENTITY Iacute "Í"> <!ENTITY Icirc "Î"> <!ENTITY Iuml "Ï"> <!ENTITY ETH "Ð"> <!ENTITY Ntilde "Ñ"> <!ENTITY Ograve "Ò"> <!ENTITY Oacute "Ó"> <!ENTITY Ocirc "Ô"> <!ENTITY Otilde "Õ"> <!ENTITY Ouml "Ö"> <!ENTITY times "×"> <!ENTITY Oslash "Ø"> <!ENTITY Ugrave "Ù"> <!ENTITY Uacute "Ú"> <!ENTITY Ucirc "Û"> <!ENTITY Uuml "Ü"> <!ENTITY Yacute "Ý"> <!ENTITY THORN "Þ"> <!ENTITY szlig "ß"> <!ENTITY agrave "à"> <!ENTITY aacute "á"> <!ENTITY acirc "â"> <!ENTITY atilde "ã"> <!ENTITY auml "ä"> <!ENTITY aring "å"> <!ENTITY aelig "æ"> <!ENTITY ccedil "ç"> <!ENTITY egrave "è"> <!ENTITY eacute "é"> <!ENTITY ecirc "ê"> <!ENTITY euml "ë"> <!ENTITY igrave "ì"> <!ENTITY iacute "í"> <!ENTITY icirc "î"> <!ENTITY iuml "ï"> <!ENTITY eth "ð"> <!ENTITY ntilde "ñ"> <!ENTITY ograve "ò"> <!ENTITY oacute "ó"> <!ENTITY ocirc "ô"> <!ENTITY otilde "õ"> <!ENTITY ouml "ö"> <!ENTITY divide "÷"> <!ENTITY oslash "ø"> <!ENTITY ugrave "ù"> <!ENTITY uacute "ú"> <!ENTITY ucirc "û"> <!ENTITY uuml "ü"> <!ENTITY yacute "ý"> <!ENTITY thorn "þ"> <!ENTITY yuml "ÿ"> <!ENTITY OElig "Œ"> <!ENTITY oelig "œ"> <!ENTITY Scaron "Š"> <!ENTITY scaron "š"> <!ENTITY Yuml "Ÿ"> <!ENTITY fnof "ƒ"> <!ENTITY circ "ˆ"> <!ENTITY tilde "˜"> <!ENTITY Alpha "Α"> <!ENTITY Beta "Β"> <!ENTITY Gamma "Γ"> <!ENTITY Epsilon "Ε"> <!ENTITY Zeta "Ζ"> <!ENTITY Eta "Η"> <!ENTITY Theta "Θ"> <!ENTITY Iota "Ι"> <!ENTITY Kappa "Κ"> <!ENTITY Lambda "Λ"> <!ENTITY Mu "Μ"> <!ENTITY Nu "Ν"> <!ENTITY Xi "Ξ"> <!ENTITY Omicron "Ο"> <!ENTITY Pi "Π"> <!ENTITY Rho "Ρ"> <!ENTITY Sigma "Σ"> <!ENTITY Tau "Τ"> <!ENTITY Upsilon "Υ"> <!ENTITY Phi "Φ"> <!ENTITY Chi "Χ"> <!ENTITY Psi "Ψ"> <!ENTITY Omega "Ω"> <!ENTITY alpha "α"> <!ENTITY beta "β"> <!ENTITY gamma "γ"> <!ENTITY delta "δ"> <!ENTITY epsilon "ε"> <!ENTITY zeta "ζ"> <!ENTITY eta "η"> <!ENTITY theta "θ"> <!ENTITY iota "ι"> <!ENTITY kappa "κ"> <!ENTITY lambda "λ"> <!ENTITY mu "μ"> <!ENTITY nu "ν"> <!ENTITY xi "ξ"> <!ENTITY omicron "ο"> <!ENTITY pi "π"> <!ENTITY rho "ρ"> <!ENTITY sigmaf "ς"> <!ENTITY sigma "σ"> <!ENTITY tau "τ"> <!ENTITY upsilon "υ"> <!ENTITY phi "φ"> <!ENTITY chi "χ"> <!ENTITY psi "ψ"> <!ENTITY omega "ω"> <!ENTITY thetasym "ϑ"> <!ENTITY upsih "ϒ"> <!ENTITY piv "ϖ"> <!ENTITY ensp " "> <!ENTITY emsp " "> <!ENTITY thinsp " "> <!ENTITY zwnj "‌"> <!ENTITY zwj "‍"> <!ENTITY lrm "‎"> <!ENTITY rlm "‏"> <!ENTITY ndash "–"> <!ENTITY mdash "—"> <!ENTITY lsquo "‘"> <!ENTITY rsquo "’"> <!ENTITY sbquo "‚"> <!ENTITY ldquo "“"> <!ENTITY rdquo "”"> <!ENTITY bdquo "„"> <!ENTITY dagger "†"> <!ENTITY Dagger "‡"> <!ENTITY bull "•"> <!ENTITY hellip "…"> <!ENTITY permil "‰"> <!ENTITY prime "′"> <!ENTITY Prime "″"> <!ENTITY lsaquo "‹"> <!ENTITY rsaquo "›"> <!ENTITY oline "‾"> <!ENTITY frasl "⁄"> <!ENTITY euro "€"> <!ENTITY image "ℑ"> <!ENTITY weierp "℘"> <!ENTITY real "ℜ"> <!ENTITY trade "™"> <!ENTITY alefsym "ℵ"> <!ENTITY larr "←"> <!ENTITY uarr "↑"> <!ENTITY rarr "→"> <!ENTITY darr "↓"> <!ENTITY harr "↔"> <!ENTITY crarr "↵"> <!ENTITY lArr "⇐"> <!ENTITY uArr "⇑"> <!ENTITY rArr "⇒"> <!ENTITY dArr "⇓"> <!ENTITY hArr "⇔"> <!ENTITY forall "∀"> <!ENTITY part "∂"> <!ENTITY exist "∃"> <!ENTITY empty "∅"> <!ENTITY nabla "∇"> <!ENTITY isin "∈"> <!ENTITY notin "∉"> <!ENTITY ni "∋"> <!ENTITY prod "∏"> <!ENTITY sum "∑"> <!ENTITY minus "−"> <!ENTITY lowast "∗"> <!ENTITY radic "√"> <!ENTITY prop "∝"> <!ENTITY infin "∞"> <!ENTITY ang "∠"> <!ENTITY and "∧"> <!ENTITY or "∨"> <!ENTITY cap "∩"> <!ENTITY cup "∪"> <!ENTITY int "∫"> <!ENTITY there4 "∴"> <!ENTITY sim "∼"> <!ENTITY cong "≅"> <!ENTITY asymp "≈"> <!ENTITY ne "≠"> <!ENTITY equiv "≡"> <!ENTITY le "≤"> <!ENTITY ge "≥"> <!ENTITY sub "⊂"> <!ENTITY sup "⊃"> <!ENTITY nsub "⊄"> <!ENTITY sube "⊆"> <!ENTITY supe "⊇"> <!ENTITY oplus "⊕"> <!ENTITY otimes "⊗"> <!ENTITY perp "⊥"> <!ENTITY sdot "⋅"> <!ENTITY lceil "⌈"> <!ENTITY rceil "⌉"> <!ENTITY lfloor "⌊"> <!ENTITY rfloor "⌋"> <!ENTITY lang "〈"> <!ENTITY rang "〉"> <!ENTITY loz "◊"> <!ENTITY spades "♠"> <!ENTITY clubs "♣"> <!ENTITY hearts "♥"> <!ENTITY diams "♦"> ]>'; } } diff --git a/lib/simplepie/simplepie/src/Sanitize.php b/lib/simplepie/simplepie/src/Sanitize.php index 1050b2266..9af3a6b12 100644 --- a/lib/simplepie/simplepie/src/Sanitize.php +++ b/lib/simplepie/simplepie/src/Sanitize.php @@ -18,8 +18,8 @@ use SimplePie\Cache\BaseDataCache; use SimplePie\Cache\CallableNameFilter; use SimplePie\Cache\DataCache; use SimplePie\Cache\NameFilter; -use SimplePie\Exception\HttpException; use SimplePie\HTTP\Client; +use SimplePie\HTTP\ClientException; use SimplePie\HTTP\FileClient; use SimplePie\HTTP\Psr18Client; @@ -504,7 +504,7 @@ class Sanitize implements RegistryAware $img->getAttribute('src'), ['X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']] ); - } catch (HttpException $th) { + } catch (ClientException $th) { continue; } diff --git a/lib/simplepie/simplepie/src/SimplePie.php b/lib/simplepie/simplepie/src/SimplePie.php index 89f7624f8..a61e7158a 100644 --- a/lib/simplepie/simplepie/src/SimplePie.php +++ b/lib/simplepie/simplepie/src/SimplePie.php @@ -20,8 +20,8 @@ use SimplePie\Cache\NameFilter; use SimplePie\Cache\Psr16; use SimplePie\Content\Type\Sniffer; use SimplePie\Exception as SimplePieException; -use SimplePie\Exception\HttpException; use SimplePie\HTTP\Client; +use SimplePie\HTTP\ClientException; use SimplePie\HTTP\FileClient; use SimplePie\HTTP\Psr18Client; use SimplePie\HTTP\Response; @@ -1997,7 +1997,7 @@ class SimplePie try { $file = $this->get_http_client()->request(Client::METHOD_GET, $this->feed_url, $headers); $this->status_code = $file->get_status_code(); - } catch (HttpException $th) { + } catch (ClientException $th) { $this->check_modified = false; $this->status_code = $th->getCode(); // FreshRSS https://github.com/simplepie/simplepie/pull/905 @@ -2090,7 +2090,7 @@ class SimplePie ]; try { $file = $this->get_http_client()->request(Client::METHOD_GET, $this->feed_url, $headers); - } catch (HttpException $th) { + } catch (ClientException $th) { // If the file connection has an error, set SimplePie::error to that and quit $this->error = $th->getMessage(); $this->status_code = $th->getCode(); // FreshRSS https://github.com/simplepie/simplepie/pull/905 @@ -2605,10 +2605,10 @@ class SimplePie if (!empty($element['xml_base_explicit']) && isset($element['xml_base'])) { return $element['xml_base']; } - if (($link = $this->get_link(0, 'self')) !== null) { + if (($link = $this->get_link(0, 'alternate')) !== null) { return $link; } - if (($link = $this->get_link(0, 'alternate')) !== null) { + if (($link = $this->get_link(0, 'self')) !== null) { return $link; } diff --git a/lib/simplepie/simplepie/utils/PHPStan/README.md b/lib/simplepie/simplepie/utils/PHPStan/README.md new file mode 100644 index 000000000..bd0cdb030 --- /dev/null +++ b/lib/simplepie/simplepie/utils/PHPStan/README.md @@ -0,0 +1,7 @@ +# SimplePie PHPStan extension + +**This extension is considered unstable, use at your own risk.** + +It provides: + +- Correct return type for `Registry::call()` diff --git a/lib/simplepie/simplepie/utils/PHPStan/RegistryCallMethodReturnTypeExtension.php b/lib/simplepie/simplepie/utils/PHPStan/RegistryCallMethodReturnTypeExtension.php new file mode 100644 index 000000000..564ba0dfa --- /dev/null +++ b/lib/simplepie/simplepie/utils/PHPStan/RegistryCallMethodReturnTypeExtension.php @@ -0,0 +1,101 @@ +<?php + +// SPDX-FileCopyrightText: 2024 Jan Tojnar +// SPDX-License-Identifier: BSD-3-Clause + +declare(strict_types=1); + +namespace SimplePieUtils\PHPStan; + +use PHPStan\Analyser\Scope; +use PHPStan\Reflection\MethodReflection; +use PHPStan\Reflection\ParametersAcceptorSelector; +use PHPStan\Type\DynamicMethodReturnTypeExtension; +use PHPStan\Type\Type; +use PHPStan\Reflection\ReflectionProvider; +use PhpParser\Node\Expr\MethodCall; +use PHPStan\Type\Constant\ConstantStringType; +use PHPStan\Type\Constant\ConstantArrayType; +use PHPStan\Type\ArrayType; +use PHPStan\Type\MixedType; + +/** + * Fixes return type for `Registry::call()` to match the called method. + */ +class RegistryCallMethodReturnTypeExtension implements DynamicMethodReturnTypeExtension +{ + /** @var ReflectionProvider */ + private $reflectionProvider; + + public function __construct(ReflectionProvider $reflectionProvider) + { + $this->reflectionProvider = $reflectionProvider; + } + + public function getClass(): string + { + return 'SimplePie\Registry'; + } + + public function isMethodSupported(MethodReflection $methodReflection): bool + { + return $methodReflection->getName() === 'call'; + } + + public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type + { + // The method will be called as `$registry->call($className, $methodName, $arguments)`. + $args = $methodCall->getArgs(); + + if (count($args) < 2) { + // Not enough arguments to determine the return type. + return new MixedType(); + } + + $classNameArg = $args[0]->value; + $methodNameArg = $args[1]->value; + $argumentsArg = $args[2]->value ?? null; + + $classType = $scope->getType($classNameArg); + $methodType = $scope->getType($methodNameArg); + + if (!$classType instanceof ConstantStringType || !$methodType instanceof ConstantStringType) { + return new MixedType(); + } + + $className = $classType->getValue(); + if (!$this->reflectionProvider->hasClass($className)) { + return new MixedType(); + } + + $classReflection = $this->reflectionProvider->getClass($className); + + $methodName = $methodType->getValue(); + if (!$classReflection->hasMethod($methodName)) { + return new MixedType(); + } + + $methodReflection = $classReflection->getMethod($methodName, $scope); + + $argumentTypes = []; + if ($argumentsArg !== null) { + $argumentsType = $scope->getType($argumentsArg); + + if ($argumentsType instanceof ConstantArrayType) { + $argumentTypes = $argumentsType->getValueTypes(); + } elseif ($argumentsType instanceof ArrayType) { + $argumentTypes = [$argumentsType->getItemType()]; + } else { + return new MixedType(); + } + } + + $parametersAcceptor = ParametersAcceptorSelector::selectFromTypes( + $argumentTypes, + $methodReflection->getVariants(), + false + ); + + return $parametersAcceptor->getReturnType(); + } +} diff --git a/lib/simplepie/simplepie/utils/PHPStan/extension.neon b/lib/simplepie/simplepie/utils/PHPStan/extension.neon new file mode 100644 index 000000000..3b6811a20 --- /dev/null +++ b/lib/simplepie/simplepie/utils/PHPStan/extension.neon @@ -0,0 +1,6 @@ + +services: + - + class: SimplePieUtils\PHPStan\RegistryCallMethodReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension |
