SimplePie bump upstream (#8628)

https://github.com/FreshRSS/simplepie/pull/71
This commit is contained in:
Alexandre Alapetite
2026-03-24 08:36:53 +01:00
committed by GitHub
parent 1f614e5b46
commit ed18aba733
11 changed files with 104 additions and 78 deletions

View File

@@ -14,7 +14,7 @@
"marienfressinaud/lib_opml": "0.5.1",
"phpgt/cssxpath": "v1.4.0",
"phpmailer/phpmailer": "7.0.2",
"simplepie/simplepie": "dev-freshrss#dbcf155c82a17872f0bf8562723cc809842064ee"
"simplepie/simplepie": "dev-freshrss#144f0823f34f6ae2ceb6bfbcc277172bb2d085b3"
},
"config": {
"sort-packages": true,

View File

@@ -14,12 +14,6 @@ parameters:
count: 1
path: src/HTTP/Psr18Client.php
# SimplePie\Content\Type\Sniffer::__construct(): Parameter $file could be mixed due to BC.
-
message: '(Result of \|\| is always false\.)'
count: 1
path: src/Content/Type/Sniffer.php
# Not used since https://github.com/simplepie/simplepie/commit/b2eb0134d53921e75f0fa70b1cf901ed82b988b1 but cannot be removed due to BC.
- '(Constructor of class SimplePie\\Enclosure has an unused parameter \$javascript\.)'

View File

@@ -27,26 +27,17 @@ class Sniffer
/**
* File object
*
* @var File|Response
* @var File
*/
public $file;
/**
* Create an instance of the class with the input file
*
* @param File|Response $file Input file
* @param File $file Input file
*/
public function __construct(/* File */ $file)
public function __construct(File $file)
{
if (!is_object($file) || !$file instanceof Response) {
// For BC we're asking for `File`, but internally we accept every `Response` implementation
throw new InvalidArgumentException(sprintf(
'%s(): Argument #1 ($file) must be of type %s',
__METHOD__,
File::class
), 1);
}
$this->file = $file;
}

View File

@@ -110,52 +110,27 @@ class File implements Response
}
if (!$force_fsockopen && function_exists('curl_exec')) {
$this->method = \SimplePie\SimplePie::FILE_SOURCE_REMOTE | \SimplePie\SimplePie::FILE_SOURCE_CURL;
$fp = curl_init();
$headers2 = [];
foreach ($headers as $key => $value) {
$headers2[] = "$key: $value";
}
if (isset($curl_options[CURLOPT_HTTPHEADER])) {
if (is_array($curl_options[CURLOPT_HTTPHEADER])) {
$headers2 = array_merge($headers2, $curl_options[CURLOPT_HTTPHEADER]);
}
unset($curl_options[CURLOPT_HTTPHEADER]);
}
if (version_compare(\SimplePie\Misc::get_curl_version(), '7.21.6', '>=')) {
curl_setopt($fp, CURLOPT_ACCEPT_ENCODING, '');
} else {
curl_setopt($fp, CURLOPT_ENCODING, '');
}
/** @var non-empty-string $url */
curl_setopt($fp, CURLOPT_URL, $url);
curl_setopt($fp, CURLOPT_RETURNTRANSFER, true);
curl_setopt($fp, CURLOPT_FAILONERROR, true);
curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
// curl_setopt($fp, CURLOPT_REFERER, \SimplePie\Misc::url_remove_credentials($url)); // FreshRSS removed
curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
$fp = self::curlInit($url, $timeout, $headers, $useragent, $curl_options);
$responseHeaders = '';
curl_setopt($fp, CURLOPT_HEADERFUNCTION, function ($ch, string $header) use (&$responseHeaders) {
$responseHeaders .= $header;
return strlen($header);
});
foreach ($curl_options as $curl_param => $curl_value) {
curl_setopt($fp, $curl_param, $curl_value);
}
$responseBody = curl_exec($fp);
$responseHeaders .= "\r\n";
if (curl_errno($fp) === CURLE_WRITE_ERROR || curl_errno($fp) === CURLE_BAD_CONTENT_ENCODING) {
$this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp); // FreshRSS
$this->on_http_response($responseBody === false ? false : $responseHeaders . $responseBody, $curl_options);
$this->error = null; // FreshRSS
if (version_compare(\SimplePie\Misc::get_curl_version(), '7.21.6', '>=')) {
curl_setopt($fp, CURLOPT_ACCEPT_ENCODING, null);
} else {
curl_setopt($fp, CURLOPT_ENCODING, null);
if (\PHP_VERSION_ID < 80000) {
curl_close($fp);
}
$fp = self::curlInit($url, $timeout, $headers, $useragent, $curl_options, false);
$responseHeaders = '';
curl_setopt($fp, CURLOPT_HEADERFUNCTION, function ($ch, string $header) use (&$responseHeaders) {
$responseHeaders .= $header;
return strlen($header);
});
$responseBody = curl_exec($fp);
$responseHeaders .= "\r\n";
}
@@ -315,7 +290,7 @@ class File implements Response
} else {
$this->method = \SimplePie\SimplePie::FILE_SOURCE_LOCAL | \SimplePie\SimplePie::FILE_SOURCE_FILE_GET_CONTENTS;
$filebody = false;
if (empty($url) || !is_readable($url) || false === $filebody = file_get_contents($url)) {
if (empty($url) || !is_readable($url) || false === ($filebody = file_get_contents($url))) {
$this->body = '';
$this->error = sprintf('file "%s" is not readable', $url);
$this->success = false;
@@ -459,10 +434,8 @@ class File implements Response
*/
final public static function fromResponse(Response $response): self
{
$headers = [];
foreach ($response->get_headers() as $name => $header) {
$headers[$name] = implode(', ', $header);
if ($response instanceof self) {
return $response;
}
/** @var File */
@@ -470,13 +443,61 @@ class File implements Response
$file->url = $response->get_final_requested_uri();
$file->useragent = null;
$file->headers = $headers;
$file->set_headers($response->get_headers());
$file->body = $response->get_body_content();
$file->status_code = $response->get_status_code();
$file->permanent_url = $response->get_permanent_uri();
return $file;
}
/**
* @param array<string, string> $headers
* @param array<int, mixed> $curl_options
* @return \CurlHandle
*/
private static function curlInit(
string $url,
int $timeout,
array $headers,
string $useragent,
array $curl_options,
bool $setAcceptEncoding = true
) {
$fp = curl_init();
$headers2 = [];
foreach ($headers as $key => $value) {
$headers2[] = "$key: $value";
}
if (isset($curl_options[CURLOPT_HTTPHEADER])) {
if (is_array($curl_options[CURLOPT_HTTPHEADER])) {
$headers2 = array_merge($headers2, $curl_options[CURLOPT_HTTPHEADER]);
}
unset($curl_options[CURLOPT_HTTPHEADER]);
}
if ($setAcceptEncoding) {
if (version_compare(\SimplePie\Misc::get_curl_version(), '7.21.6', '>=')) {
curl_setopt($fp, CURLOPT_ACCEPT_ENCODING, '');
} else {
curl_setopt($fp, CURLOPT_ENCODING, '');
}
}
/** @var non-empty-string $url */
curl_setopt($fp, CURLOPT_URL, $url);
curl_setopt($fp, CURLOPT_RETURNTRANSFER, true);
curl_setopt($fp, CURLOPT_FAILONERROR, true);
curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
// curl_setopt($fp, CURLOPT_REFERER, \SimplePie\Misc::url_remove_credentials($url)); // FreshRSS removed
curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
foreach ($curl_options as $curl_param => $curl_value) {
curl_setopt($fp, $curl_param, $curl_value);
}
return $fp;
}
}
class_alias('SimplePie\File', 'SimplePie_File');

View File

@@ -12,6 +12,7 @@ use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\UriFactoryInterface;
use SimplePie\Misc;
use Throwable;
/**
@@ -82,7 +83,7 @@ final class Psr18Client implements Client
), 1);
}
if (preg_match('/^http(s)?:\/\//i', $url)) {
if (Misc::is_remote_uri($url)) {
return $this->requestUrl($method, $url, $headers);
}
@@ -119,7 +120,7 @@ final class Psr18Client implements Client
$statusCode = $response->getStatusCode();
// If we have a redirect
if (in_array($statusCode, [300, 301, 302, 303, 307]) && $response->hasHeader('Location')) {
if (in_array($statusCode, [300, 301, 302, 303, 307, 308]) && $response->hasHeader('Location')) {
// Prevent infinity redirect loops
if ($remainingRedirects <= 0) {
break;
@@ -130,7 +131,7 @@ final class Psr18Client implements Client
$requestedUrl = $response->getHeaderLine('Location');
if ($statusCode === 301) {
if ($statusCode === 301 || $statusCode === 308) {
$permanentUrl = $requestedUrl;
}

View File

@@ -32,13 +32,13 @@ final class Psr7Response implements Response
/**
* @var string
*/
private $requested_url;
private $final_requested_url;
public function __construct(ResponseInterface $response, string $permanent_url, string $requested_url)
public function __construct(ResponseInterface $response, string $permanent_url, string $final_requested_url)
{
$this->response = $response;
$this->permanent_url = $permanent_url;
$this->requested_url = $requested_url;
$this->final_requested_url = $final_requested_url;
}
public function get_permanent_uri(): string
@@ -48,7 +48,7 @@ final class Psr7Response implements Response
public function get_final_requested_uri(): string
{
return $this->requested_url;
return $this->final_requested_url;
}
public function get_status_code(): int
@@ -71,7 +71,7 @@ final class Psr7Response implements Response
public function with_header(string $name, $value)
{
return new self($this->response->withHeader($name, $value), $this->permanent_url, $this->requested_url);
return new self($this->response->withHeader($name, $value), $this->permanent_url, $this->final_requested_url);
}
public function get_header(string $name): array
@@ -86,6 +86,6 @@ final class Psr7Response implements Response
public function get_body_content(): string
{
return $this->response->getBody()->__toString();
return (string) $this->response->getBody();
}
}

View File

@@ -28,20 +28,20 @@ final class RawTextResponse implements Response
private $permanent_url;
/**
* @var array<non-empty-array<string>>
* @var array<string, non-empty-array<string>>
*/
private $headers = [];
/**
* @var string
*/
private $requested_url;
private $final_requested_url;
public function __construct(string $raw_text, string $filepath)
{
$this->raw_text = $raw_text;
$this->permanent_url = $filepath;
$this->requested_url = $filepath;
$this->final_requested_url = $filepath;
}
public function get_permanent_uri(): string
@@ -51,7 +51,7 @@ final class RawTextResponse implements Response
public function get_final_requested_uri(): string
{
return $this->requested_url;
return $this->final_requested_url;
}
public function get_status_code(): int

View File

@@ -26,9 +26,9 @@ use SimplePie\HTTP\Response;
class Locator implements RegistryAware
{
/** @var ?string */
public $useragent = null;
public $useragent;
/** @var int */
public $timeout = 10;
public $timeout;
/** @var File */
public $file;
/** @var string[] */
@@ -46,11 +46,11 @@ class Locator implements RegistryAware
/** @var int */
public $checked_feeds = 0;
/** @var int */
public $max_checked_feeds = 10;
public $max_checked_feeds;
/** @var bool */
public $force_fsockopen = false;
public $force_fsockopen;
/** @var array<int, mixed> */
public $curl_options = [];
public $curl_options;
/** @var ?\DomDocument */
public $dom;
/** @var ?Registry */
@@ -167,7 +167,8 @@ class Locator implements RegistryAware
assert($this->registry !== null);
if (Misc::is_remote_uri($file->get_final_requested_uri())) {
$sniffer = $this->registry->create(Content\Type\Sniffer::class, [$file]);
$fileResponse = File::fromResponse($file);
$sniffer = $this->registry->create(Content\Type\Sniffer::class, [$fileResponse]);
$sniffed = $sniffer->get_type();
$mime_types = ['application/rss+xml', 'application/rdf+xml',
'text/rdf', 'application/atom+xml', 'text/xml',

View File

@@ -2282,7 +2282,8 @@ class SimplePie
$headers[$key] = implode(', ', $values);
}
$sniffer = $this->registry->create(Sniffer::class, [&$file]);
$fileResponse = File::fromResponse($file);
$sniffer = $this->registry->create(Sniffer::class, [$fileResponse]);
$sniffed = $sniffer->get_type();
return [$headers, $sniffed];

View File

@@ -1,3 +1,5 @@
includes:
- version_dependent.php
services:
-

View File

@@ -0,0 +1,15 @@
<?php
namespace SimplePieUtils\PHPStan;
$typeAliases = [];
if (PHP_VERSION_ID < 80000) {
$typeAliases['\CurlHandle'] = 'resource';
}
return [
'parameters' => [
'typeAliases' => $typeAliases,
],
];