Make WordPress Core


Ignore:
Timestamp:
09/16/2025 10:45:37 PM (2 months ago)
Author:
SergeyBiryukov
Message:

External Libraries: Update the SimplePie library to version 1.9.0.

References:

Follow-up to [59141], [60490].

Props swissspidy, TobiasBg, SergeyBiryukov.
Fixes #63961.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/SimplePie/src/SimplePie.php

    r60490 r60771  
    11<?php
    22
    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  */
     3// SPDX-FileCopyrightText: 2004-2023 Ryan Parman, Sam Sneddon, Ryan McCue
     4// SPDX-License-Identifier: BSD-3-Clause
     5
     6declare(strict_types=1);
    447
    458namespace SimplePie;
    469
    4710use InvalidArgumentException;
     11use Psr\Http\Client\ClientInterface;
     12use Psr\Http\Message\RequestFactoryInterface;
     13use Psr\Http\Message\UriFactoryInterface;
    4814use Psr\SimpleCache\CacheInterface;
    4915use SimplePie\Cache\Base;
     
    5420use SimplePie\Cache\Psr16;
    5521use SimplePie\Content\Type\Sniffer;
     22use SimplePie\Exception as SimplePieException;
     23use SimplePie\HTTP\Client;
     24use SimplePie\HTTP\ClientException;
     25use SimplePie\HTTP\FileClient;
     26use SimplePie\HTTP\Psr18Client;
     27use SimplePie\HTTP\Response;
    5628
    5729/**
    5830 * SimplePie
    59  *
    60  * @package SimplePie
    61  * @subpackage API
    6231 */
    6332class SimplePie
     
    7140     * SimplePie Version
    7241     */
    73     public const VERSION = '1.8.1';
     42    public const VERSION = '1.9.0';
    7443
    7544    /**
     
    412381
    413382    /**
    414      * @var array Raw data
     383     * @internal Default value of the HTTP Accept header when fetching/locating feeds
     384     */
     385    public const DEFAULT_HTTP_ACCEPT_HEADER = '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';
     386
     387    /**
     388     * @var array<string, mixed> Raw data
    415389     * @access private
    416390     */
     
    418392
    419393    /**
    420      * @var mixed Error string
     394     * @var string|string[]|null Error string (or array when multiple feeds are initialized)
    421395     * @access private
    422396     */
    423     public $error;
     397    public $error = null;
    424398
    425399    /**
     
    431405
    432406    /**
    433      * @var object Instance of \SimplePie\Sanitize (or other class)
     407     * @var Sanitize instance of Sanitize class
    434408     * @see SimplePie::set_sanitize_class()
    435409     * @access private
     
    452426
    453427    /**
    454      * @var string Original feed URL, or new feed URL iff HTTP 301 Moved Permanently
     428     * @var ?string Original feed URL, or new feed URL iff HTTP 301 Moved Permanently
    455429     * @see SimplePie::subscribe_url()
    456430     * @access private
     
    459433
    460434    /**
    461      * @var object Instance of \SimplePie\File to use as a feed
     435     * @var File Instance of File class to use as a feed
    462436     * @see SimplePie::set_file()
    463      * @access private
    464      */
    465     public $file;
    466 
    467     /**
    468      * @var string Raw feed data
     437     */
     438    private $file;
     439
     440    /**
     441     * @var string|false Raw feed data
    469442     * @see SimplePie::set_raw_data()
    470443     * @access private
     
    480453
    481454    /**
    482      * @var array Custom curl options
     455     * @var array<int, mixed> Custom curl options
    483456     * @see SimplePie::set_curl_options()
    484457     * @access private
     
    551524
    552525    /**
    553      * @var string Function that creates the cache filename
     526     * @var string&(callable(string): string) Function that creates the cache filename
    554527     * @see SimplePie::set_cache_name_function()
    555528     * @access private
     
    573546
    574547    /**
    575      * @var int Feed Autodiscovery Level
     548     * @var self::LOCATOR_* Feed Autodiscovery Level
    576549     * @see SimplePie::set_autodiscovery_level()
    577550     * @access private
     
    582555     * Class registry object
    583556     *
    584      * @var \SimplePie\Registry
     557     * @var Registry
    585558     */
    586559    public $registry;
     
    594567
    595568    /**
    596      * @var array All the feeds found during the autodiscovery process
     569     * @var array<Response>|null All the feeds found during the autodiscovery process
    597570     * @see SimplePie::get_all_discovered_feeds()
    598571     * @access private
     
    608581
    609582    /**
    610      * @var array Stores the URLs when multiple feeds are being initialized.
     583     * @var array<string> Stores the URLs when multiple feeds are being initialized.
    611584     * @see SimplePie::set_feed_url()
    612585     * @access private
     
    615588
    616589    /**
    617      * @var array Stores SimplePie objects when multiple feeds initialized.
     590     * @var array<int, static> Stores SimplePie objects when multiple feeds initialized.
    618591     * @access private
    619592     */
     
    621594
    622595    /**
    623      * @var array Stores the get_object_vars() array for use with multifeeds.
     596     * @var array<mixed> Stores the get_object_vars() array for use with multifeeds.
    624597     * @see SimplePie::set_feed_url()
    625598     * @access private
     
    628601
    629602    /**
    630      * @var integer Stores the number of items to return per-feed with multifeeds.
     603     * @var int Stores the number of items to return per-feed with multifeeds.
    631604     * @see SimplePie::set_item_limit()
    632605     * @access private
     
    641614
    642615    /**
    643      * @var array Stores the default attributes to be stripped by strip_attributes().
     616     * @var array<string> Stores the default attributes to be stripped by strip_attributes().
    644617     * @see SimplePie::strip_attributes()
    645618     * @access private
     
    648621
    649622    /**
    650      * @var array Stores the default attributes to add to different tags by add_attributes().
     623     * @var array<string, array<string, string>> Stores the default attributes to add to different tags by add_attributes().
    651624     * @see SimplePie::add_attributes()
    652625     * @access private
     
    655628
    656629    /**
    657      * @var array Stores the default tags to be stripped by strip_htmltags().
     630     * @var array<string> Stores the default tags to be stripped by strip_htmltags().
    658631     * @see SimplePie::strip_htmltags()
    659632     * @access private
     
    662635
    663636    /**
    664      * @var array Stores the default attributes to be renamed by rename_attributes().
     637     * @var string[]|string Stores the default attributes to be renamed by rename_attributes().
    665638     * @see SimplePie::rename_attributes()
    666639     * @access private
     
    673646     */
    674647    public $enable_exceptions = false;
     648
     649    /**
     650     * @var Client|null
     651     */
     652    private $http_client = null;
     653
     654    /** @var bool Whether HTTP client has been injected */
     655    private $http_client_injected = false;
    675656
    676657    /**
     
    699680
    700681        // Other objects, instances created here so we can set options on them
    701         $this->sanitize = new \SimplePie\Sanitize();
    702         $this->registry = new \SimplePie\Registry();
     682        $this->sanitize = new Sanitize();
     683        $this->registry = new Registry();
    703684
    704685        if (func_num_args() > 0) {
     
    722703    /**
    723704     * Used for converting object to a string
     705     * @return string
    724706     */
    725707    public function __toString()
     
    730712    /**
    731713     * Remove items that link back to this before destroying this object
     714     * @return void
    732715     */
    733716    public function __destruct()
     
    757740     * @since 1.1
    758741     * @param bool $enable Force the given data/URL to be treated as a feed
    759      */
    760     public function force_feed($enable = false)
    761     {
    762         $this->force_feed = (bool) $enable;
     742     * @return void
     743     */
     744    public function force_feed(bool $enable = false)
     745    {
     746        $this->force_feed = $enable;
    763747    }
    764748
     
    770754     * over any set raw data.
    771755     *
    772      * You can set multiple feeds to mash together by passing an array instead
     756     * Deprecated since 1.9.0: You can set multiple feeds to mash together by passing an array instead
    773757     * of a string for the $url. Remember that with each additional feed comes
    774758     * additional processing and resources.
     
    776760     * @since 1.0 Preview Release
    777761     * @see set_raw_data()
    778      * @param string|array $url This is the URL (or array of URLs) that you want to parse.
     762     * @param string|string[] $url This is the URL (or (deprecated) array of URLs) that you want to parse.
     763     * @return void
    779764     */
    780765    public function set_feed_url($url)
     
    782767        $this->multifeed_url = [];
    783768        if (is_array($url)) {
     769            trigger_error('Fetching multiple feeds with single SimplePie instance is deprecated since SimplePie 1.9.0, create one SimplePie instance per feed and use SimplePie::merge_items to get a single list of items.', \E_USER_DEPRECATED);
    784770            foreach ($url as $value) {
    785771                $this->multifeed_url[] = $this->registry->call(Misc::class, 'fix_protocol', [$value, 1]);
     
    792778
    793779    /**
    794      * Set an instance of {@see \SimplePie\File} to use as a feed
    795      *
    796      * @param \SimplePie\File &$file
     780     * Set an instance of {@see File} to use as a feed
     781     *
     782     * @deprecated since SimplePie 1.9.0, use \SimplePie\SimplePie::set_http_client() or \SimplePie\SimplePie::set_raw_data() instead.
     783     *
     784     * @param File &$file
    797785     * @return bool True on success, false on failure
    798786     */
    799     public function set_file(&$file)
    800     {
    801         if ($file instanceof \SimplePie\File) {
    802             $this->feed_url = $file->url;
    803             $this->permanent_url = $this->feed_url;
    804             $this->file = &$file;
    805             return true;
    806         }
    807         return false;
     787    public function set_file(File &$file)
     788    {
     789        // trigger_error(sprintf('SimplePie\SimplePie::set_file() is deprecated since SimplePie 1.9.0, please use "SimplePie\SimplePie::set_http_client()" or "SimplePie\SimplePie::set_raw_data()" instead.'), \E_USER_DEPRECATED);
     790
     791        $this->feed_url = $file->get_final_requested_uri();
     792        $this->permanent_url = $this->feed_url;
     793        $this->file = &$file;
     794
     795        return true;
    808796    }
    809797
     
    820808     * @param string $data RSS or Atom data as a string.
    821809     * @see set_feed_url()
    822      */
    823     public function set_raw_data($data)
     810     * @return void
     811     */
     812    public function set_raw_data(string $data)
    824813    {
    825814        $this->raw_data = $data;
     815    }
     816
     817    /**
     818     * Set a PSR-18 client and PSR-17 factories
     819     *
     820     * Allows you to use your own HTTP client implementations.
     821     * This will become required with SimplePie 2.0.0.
     822     */
     823    final public function set_http_client(
     824        ClientInterface $http_client,
     825        RequestFactoryInterface $request_factory,
     826        UriFactoryInterface $uri_factory
     827    ): void {
     828        $this->http_client = new Psr18Client($http_client, $request_factory, $uri_factory);
    826829    }
    827830
     
    834837     * @since 1.0 Beta 3
    835838     * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
    836      */
    837     public function set_timeout($timeout = 10)
    838     {
     839     * @return void
     840     */
     841    public function set_timeout(int $timeout = 10)
     842    {
     843        if ($this->http_client_injected) {
     844            throw new SimplePieException(sprintf(
     845                'Using "%s()" has no effect, because you already provided a HTTP client with "%s::set_http_client()". Configure timeout in your HTTP client instead.',
     846                __METHOD__,
     847                self::class
     848            ));
     849        }
     850
    839851        $this->timeout = (int) $timeout;
     852
     853        // Reset a possible existing FileClient,
     854        // so a new client with the changed value will be created
     855        if (is_object($this->http_client) && $this->http_client instanceof FileClient) {
     856            $this->http_client = null;
     857        } elseif (is_object($this->http_client)) {
     858            // Trigger notice if a PSR-18 client was set
     859            trigger_error(sprintf(
     860                'Using "%s()" has no effect, because you already provided a HTTP client with "%s::set_http_client()". Configure the timeout in your HTTP client instead.',
     861                __METHOD__,
     862                get_class($this)
     863            ), \E_USER_NOTICE);
     864        }
    840865    }
    841866
     
    846871     *
    847872     * @since 1.0 Beta 3
    848      * @param array $curl_options Curl options to add to default settings
     873     * @param array<int, mixed> $curl_options Curl options to add to default settings
     874     * @return void
    849875     */
    850876    public function set_curl_options(array $curl_options = [])
    851877    {
     878        if ($this->http_client_injected) {
     879            throw new SimplePieException(sprintf(
     880                'Using "%s()" has no effect, because you already provided a HTTP client with "%s::set_http_client()". Configure custom curl options in your HTTP client instead.',
     881                __METHOD__,
     882                self::class
     883            ));
     884        }
     885
    852886        $this->curl_options = $curl_options;
     887
     888        // Reset a possible existing FileClient,
     889        // so a new client with the changed value will be created
     890        if (is_object($this->http_client) && $this->http_client instanceof FileClient) {
     891            $this->http_client = null;
     892        } elseif (is_object($this->http_client)) {
     893            // Trigger notice if a PSR-18 client was set
     894            trigger_error(sprintf(
     895                'Using "%s()" has no effect, because you already provided a HTTP client with "%s::set_http_client()". Configure the curl options in your HTTP client instead.',
     896                __METHOD__,
     897                get_class($this)
     898            ), \E_USER_NOTICE);
     899        }
    853900    }
    854901
     
    858905     * @since 1.0 Beta 3
    859906     * @param bool $enable Force fsockopen() to be used
    860      */
    861     public function force_fsockopen($enable = false)
    862     {
    863         $this->force_fsockopen = (bool) $enable;
     907     * @return void
     908     */
     909    public function force_fsockopen(bool $enable = false)
     910    {
     911        if ($this->http_client_injected) {
     912            throw new SimplePieException(sprintf(
     913                'Using "%s()" has no effect, because you already provided a HTTP client with "%s::set_http_client()". Configure fsockopen in your HTTP client instead.',
     914                __METHOD__,
     915                self::class
     916            ));
     917        }
     918
     919        $this->force_fsockopen = $enable;
     920
     921        // Reset a possible existing FileClient,
     922        // so a new client with the changed value will be created
     923        if (is_object($this->http_client) && $this->http_client instanceof FileClient) {
     924            $this->http_client = null;
     925        } elseif (is_object($this->http_client)) {
     926            // Trigger notice if a PSR-18 client was set
     927            trigger_error(sprintf(
     928                'Using "%s()" has no effect, because you already provided a HTTP client with "%s::set_http_client()". Configure fsockopen in your HTTP client instead.',
     929                __METHOD__,
     930                get_class($this)
     931            ), \E_USER_NOTICE);
     932        }
    864933    }
    865934
     
    872941     * @since 1.0 Preview Release
    873942     * @param bool $enable Enable caching
    874      */
    875     public function enable_cache($enable = true)
    876     {
    877         $this->enable_cache = (bool) $enable;
     943     * @return void
     944     */
     945    public function enable_cache(bool $enable = true)
     946    {
     947        $this->enable_cache = $enable;
    878948    }
    879949
     
    881951     * Set a PSR-16 implementation as cache
    882952     *
    883      * @param CacheInterface $psr16cache The PSR-16 cache implementation
     953     * @param CacheInterface $cache The PSR-16 cache implementation
    884954     *
    885955     * @return void
     
    901971     *
    902972     * @param bool $enable Force use of cache on fail.
    903      */
    904     public function force_cache_fallback($enable = false)
     973     * @return void
     974     */
     975    public function force_cache_fallback(bool $enable = false)
    905976    {
    906977        // @trigger_error(sprintf('SimplePie\SimplePie::force_cache_fallback() is deprecated since SimplePie 1.8.0, expired cache will not be used anymore.'), \E_USER_DEPRECATED);
    907         $this->force_cache_fallback = (bool) $enable;
     978        $this->force_cache_fallback = $enable;
    908979    }
    909980
     
    913984     *
    914985     * @param int $seconds The feed content cache duration
    915      */
    916     public function set_cache_duration($seconds = 3600)
    917     {
    918         $this->cache_duration = (int) $seconds;
     986     * @return void
     987     */
     988    public function set_cache_duration(int $seconds = 3600)
     989    {
     990        $this->cache_duration = $seconds;
    919991    }
    920992
     
    924996     *
    925997     * @param int $seconds The autodiscovered feed URL cache duration.
    926      */
    927     public function set_autodiscovery_cache_duration($seconds = 604800)
    928     {
    929         $this->autodiscovery_cache_duration = (int) $seconds;
     998     * @return void
     999     */
     1000    public function set_autodiscovery_cache_duration(int $seconds = 604800)
     1001    {
     1002        $this->autodiscovery_cache_duration = $seconds;
    9301003    }
    9311004
     
    9331006     * Set the file system location where the cached files should be stored
    9341007     *
    935      * @deprecated since SimplePie 1.8.0, use \SimplePie\SimplePie::set_cache() instead.
     1008     * @deprecated since SimplePie 1.8.0, use SimplePie::set_cache() instead.
    9361009     *
    9371010     * @param string $location The file system location.
    938      */
    939     public function set_cache_location($location = './cache')
     1011     * @return void
     1012     */
     1013    public function set_cache_location(string $location = './cache')
    9401014    {
    9411015        // @trigger_error(sprintf('SimplePie\SimplePie::set_cache_location() is deprecated since SimplePie 1.8.0, please use "SimplePie\SimplePie::set_cache()" instead.'), \E_USER_DEPRECATED);
    942         $this->cache_location = (string) $location;
     1016        $this->cache_location = $location;
    9431017    }
    9441018
     
    9491023     * @return string A filename (i.e. hash, without path and without extension).
    9501024     */
    951     public function get_cache_filename($url)
     1025    public function get_cache_filename(string $url)
    9521026    {
    9531027        // Append custom parameters to the URL to avoid cache pollution in case of multiple calls with different parameters.
     
    9571031            $options[CURLOPT_TIMEOUT] = $this->timeout;
    9581032        }
    959         if ($this->useragent !== \SimplePie\Misc::get_default_useragent()) {
     1033        if ($this->useragent !== Misc::get_default_useragent()) {
    9601034            $options[CURLOPT_USERAGENT] = $this->useragent;
    9611035        }
     
    9771051     *
    9781052     * @param bool $enable Sort as reverse chronological order.
    979      */
    980     public function enable_order_by_date($enable = true)
    981     {
    982         $this->order_by_date = (bool) $enable;
     1053     * @return void
     1054     */
     1055    public function enable_order_by_date(bool $enable = true)
     1056    {
     1057        $this->order_by_date = $enable;
    9831058    }
    9841059
     
    9891064     * back to the normal encoding detection if the override fails
    9901065     *
    991      * @param string $encoding Character encoding
     1066     * @param string|false $encoding Character encoding
     1067     * @return void
    9921068     */
    9931069    public function set_input_encoding($encoding = false)
     
    10031079     * Set how much feed autodiscovery to do
    10041080     *
    1005      * @see \SimplePie\SimplePie::LOCATOR_NONE
    1006      * @see \SimplePie\SimplePie::LOCATOR_AUTODISCOVERY
    1007      * @see \SimplePie\SimplePie::LOCATOR_LOCAL_EXTENSION
    1008      * @see \SimplePie\SimplePie::LOCATOR_LOCAL_BODY
    1009      * @see \SimplePie\SimplePie::LOCATOR_REMOTE_EXTENSION
    1010      * @see \SimplePie\SimplePie::LOCATOR_REMOTE_BODY
    1011      * @see \SimplePie\SimplePie::LOCATOR_ALL
    1012      * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator)
    1013      */
    1014     public function set_autodiscovery_level($level = self::LOCATOR_ALL)
    1015     {
    1016         $this->autodiscovery = (int) $level;
     1081     * @see self::LOCATOR_NONE
     1082     * @see self::LOCATOR_AUTODISCOVERY
     1083     * @see self::LOCATOR_LOCAL_EXTENSION
     1084     * @see self::LOCATOR_LOCAL_BODY
     1085     * @see self::LOCATOR_REMOTE_EXTENSION
     1086     * @see self::LOCATOR_REMOTE_BODY
     1087     * @see self::LOCATOR_ALL
     1088     * @param self::LOCATOR_* $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator)
     1089     * @return void
     1090     */
     1091    public function set_autodiscovery_level(int $level = self::LOCATOR_ALL)
     1092    {
     1093        $this->autodiscovery = $level;
    10171094    }
    10181095
     
    10211098     *
    10221099     * Use this to override SimplePie's default classes
    1023      * @see \SimplePie\Registry
    10241100     *
    10251101     * @return Registry
     
    10351111     * @deprecated since SimplePie 1.3, use {@see set_cache()} instead
    10361112     *
    1037      * @param string $class Name of custom class
    1038      *
    1039      * @return boolean True on success, false otherwise
    1040      */
    1041     public function set_cache_class($class = Cache::class)
    1042     {
    1043         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::set_cache()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1113     * @param class-string<Cache> $class Name of custom class
     1114     *
     1115     * @return bool True on success, false otherwise
     1116     */
     1117    public function set_cache_class(string $class = Cache::class)
     1118    {
     1119        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::set_cache()" instead.', __METHOD__), \E_USER_DEPRECATED);
    10441120
    10451121        return $this->registry->register(Cache::class, $class, true);
     
    10511127     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    10521128     *
    1053      * @param string $class Name of custom class
    1054      *
    1055      * @return boolean True on success, false otherwise
    1056      */
    1057     public function set_locator_class($class = Locator::class)
    1058     {
    1059         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1129     * @param class-string<Locator> $class Name of custom class
     1130     *
     1131     * @return bool True on success, false otherwise
     1132     */
     1133    public function set_locator_class(string $class = Locator::class)
     1134    {
     1135        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    10601136
    10611137        return $this->registry->register(Locator::class, $class, true);
     
    10671143     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    10681144     *
    1069      * @param string $class Name of custom class
    1070      *
    1071      * @return boolean True on success, false otherwise
    1072      */
    1073     public function set_parser_class($class = Parser::class)
    1074     {
    1075         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1145     * @param class-string<Parser> $class Name of custom class
     1146     *
     1147     * @return bool True on success, false otherwise
     1148     */
     1149    public function set_parser_class(string $class = Parser::class)
     1150    {
     1151        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    10761152
    10771153        return $this->registry->register(Parser::class, $class, true);
     
    10831159     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    10841160     *
    1085      * @param string $class Name of custom class
    1086      *
    1087      * @return boolean True on success, false otherwise
    1088      */
    1089     public function set_file_class($class = File::class)
    1090     {
    1091         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1161     * @param class-string<File> $class Name of custom class
     1162     *
     1163     * @return bool True on success, false otherwise
     1164     */
     1165    public function set_file_class(string $class = File::class)
     1166    {
     1167        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    10921168
    10931169        return $this->registry->register(File::class, $class, true);
     
    10991175     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    11001176     *
    1101      * @param string $class Name of custom class
    1102      *
    1103      * @return boolean True on success, false otherwise
    1104      */
    1105     public function set_sanitize_class($class = Sanitize::class)
    1106     {
    1107         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1177     * @param class-string<Sanitize> $class Name of custom class
     1178     *
     1179     * @return bool True on success, false otherwise
     1180     */
     1181    public function set_sanitize_class(string $class = Sanitize::class)
     1182    {
     1183        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    11081184
    11091185        return $this->registry->register(Sanitize::class, $class, true);
     
    11151191     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    11161192     *
    1117      * @param string $class Name of custom class
    1118      *
    1119      * @return boolean True on success, false otherwise
    1120      */
    1121     public function set_item_class($class = Item::class)
    1122     {
    1123         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1193     * @param class-string<Item> $class Name of custom class
     1194     *
     1195     * @return bool True on success, false otherwise
     1196     */
     1197    public function set_item_class(string $class = Item::class)
     1198    {
     1199        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    11241200
    11251201        return $this->registry->register(Item::class, $class, true);
     
    11311207     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    11321208     *
    1133      * @param string $class Name of custom class
    1134      *
    1135      * @return boolean True on success, false otherwise
    1136      */
    1137     public function set_author_class($class = Author::class)
    1138     {
    1139         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1209     * @param class-string<Author> $class Name of custom class
     1210     *
     1211     * @return bool True on success, false otherwise
     1212     */
     1213    public function set_author_class(string $class = Author::class)
     1214    {
     1215        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    11401216
    11411217        return $this->registry->register(Author::class, $class, true);
     
    11471223     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    11481224     *
    1149      * @param string $class Name of custom class
    1150      *
    1151      * @return boolean True on success, false otherwise
    1152      */
    1153     public function set_category_class($class = Category::class)
    1154     {
    1155         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1225     * @param class-string<Category> $class Name of custom class
     1226     *
     1227     * @return bool True on success, false otherwise
     1228     */
     1229    public function set_category_class(string $class = Category::class)
     1230    {
     1231        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    11561232
    11571233        return $this->registry->register(Category::class, $class, true);
     
    11631239     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    11641240     *
    1165      * @param string $class Name of custom class
    1166      *
    1167      * @return boolean True on success, false otherwise
    1168      */
    1169     public function set_enclosure_class($class = Enclosure::class)
    1170     {
    1171         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1241     * @param class-string<Enclosure> $class Name of custom class
     1242     *
     1243     * @return bool True on success, false otherwise
     1244     */
     1245    public function set_enclosure_class(string $class = Enclosure::class)
     1246    {
     1247        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    11721248
    11731249        return $this->registry->register(Enclosure::class, $class, true);
     
    11791255     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    11801256     *
    1181      * @param string $class Name of custom class
    1182      *
    1183      * @return boolean True on success, false otherwise
    1184      */
    1185     public function set_caption_class($class = Caption::class)
    1186     {
    1187         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1257     * @param class-string<Caption> $class Name of custom class
     1258     *
     1259     * @return bool True on success, false otherwise
     1260     */
     1261    public function set_caption_class(string $class = Caption::class)
     1262    {
     1263        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    11881264
    11891265        return $this->registry->register(Caption::class, $class, true);
     
    11951271     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    11961272     *
    1197      * @param string $class Name of custom class
    1198      *
    1199      * @return boolean True on success, false otherwise
    1200      */
    1201     public function set_copyright_class($class = Copyright::class)
    1202     {
    1203         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1273     * @param class-string<Copyright> $class Name of custom class
     1274     *
     1275     * @return bool True on success, false otherwise
     1276     */
     1277    public function set_copyright_class(string $class = Copyright::class)
     1278    {
     1279        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    12041280
    12051281        return $this->registry->register(Copyright::class, $class, true);
     
    12111287     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    12121288     *
    1213      * @param string $class Name of custom class
    1214      *
    1215      * @return boolean True on success, false otherwise
    1216      */
    1217     public function set_credit_class($class = Credit::class)
    1218     {
    1219         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1289     * @param class-string<Credit> $class Name of custom class
     1290     *
     1291     * @return bool True on success, false otherwise
     1292     */
     1293    public function set_credit_class(string $class = Credit::class)
     1294    {
     1295        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    12201296
    12211297        return $this->registry->register(Credit::class, $class, true);
     
    12271303     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    12281304     *
    1229      * @param string $class Name of custom class
    1230      *
    1231      * @return boolean True on success, false otherwise
    1232      */
    1233     public function set_rating_class($class = Rating::class)
    1234     {
    1235         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1305     * @param class-string<Rating> $class Name of custom class
     1306     *
     1307     * @return bool True on success, false otherwise
     1308     */
     1309    public function set_rating_class(string $class = Rating::class)
     1310    {
     1311        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    12361312
    12371313        return $this->registry->register(Rating::class, $class, true);
     
    12431319     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    12441320     *
    1245      * @param string $class Name of custom class
    1246      *
    1247      * @return boolean True on success, false otherwise
    1248      */
    1249     public function set_restriction_class($class = Restriction::class)
    1250     {
    1251         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1321     * @param class-string<Restriction> $class Name of custom class
     1322     *
     1323     * @return bool True on success, false otherwise
     1324     */
     1325    public function set_restriction_class(string $class = Restriction::class)
     1326    {
     1327        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    12521328
    12531329        return $this->registry->register(Restriction::class, $class, true);
     
    12591335     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    12601336     *
    1261      * @param string $class Name of custom class
    1262      *
    1263      * @return boolean True on success, false otherwise
    1264      */
    1265     public function set_content_type_sniffer_class($class = Sniffer::class)
    1266     {
    1267         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1337     * @param class-string<Sniffer> $class Name of custom class
     1338     *
     1339     * @return bool True on success, false otherwise
     1340     */
     1341    public function set_content_type_sniffer_class(string $class = Sniffer::class)
     1342    {
     1343        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    12681344
    12691345        return $this->registry->register(Sniffer::class, $class, true);
     
    12751351     * @deprecated since SimplePie 1.3, use {@see get_registry()} instead
    12761352     *
    1277      * @param string $class Name of custom class
    1278      *
    1279      * @return boolean True on success, false otherwise
    1280      */
    1281     public function set_source_class($class = Source::class)
    1282     {
    1283         // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
     1353     * @param class-string<Source> $class Name of custom class
     1354     *
     1355     * @return bool True on success, false otherwise
     1356     */
     1357    public function set_source_class(string $class = Source::class)
     1358    {
     1359        trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED);
    12841360
    12851361        return $this->registry->register(Source::class, $class, true);
     
    12901366     *
    12911367     * @param string $ua New user agent string.
    1292      */
    1293     public function set_useragent($ua = null)
    1294     {
     1368     * @return void
     1369     */
     1370    public function set_useragent(?string $ua = null)
     1371    {
     1372        if ($this->http_client_injected) {
     1373            throw new SimplePieException(sprintf(
     1374                'Using "%s()" has no effect, because you already provided a HTTP client with "%s::set_http_client()". Configure user agent string in your HTTP client instead.',
     1375                __METHOD__,
     1376                self::class
     1377            ));
     1378        }
     1379
    12951380        if ($ua === null) {
    1296             $ua = \SimplePie\Misc::get_default_useragent();
     1381            $ua = Misc::get_default_useragent();
    12971382        }
    12981383
    12991384        $this->useragent = (string) $ua;
     1385
     1386        // Reset a possible existing FileClient,
     1387        // so a new client with the changed value will be created
     1388        if (is_object($this->http_client) && $this->http_client instanceof FileClient) {
     1389            $this->http_client = null;
     1390        } elseif (is_object($this->http_client)) {
     1391            // Trigger notice if a PSR-18 client was set
     1392            trigger_error(sprintf(
     1393                'Using "%s()" has no effect, because you already provided a HTTP client with "%s::set_http_client()". Configure the useragent in your HTTP client instead.',
     1394                __METHOD__,
     1395                get_class($this)
     1396            ), \E_USER_NOTICE);
     1397        }
    13001398    }
    13011399
     
    13171415     * @deprecated since SimplePie 1.8.0, use {@see set_cache_namefilter()} instead
    13181416     *
    1319      * @param mixed $function Callback function
    1320      */
    1321     public function set_cache_name_function($function = 'md5')
     1417     * @param (string&(callable(string): string))|null $function Callback function
     1418     * @return void
     1419     */
     1420    public function set_cache_name_function(?string $function = null)
    13221421    {
    13231422        // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.8.0, please use "SimplePie\SimplePie::set_cache_namefilter()" instead.', __METHOD__), \E_USER_DEPRECATED);
    13241423
    1325         if (is_callable($function)) {
    1326             $this->cache_name_function = $function;
    1327 
    1328             $this->set_cache_namefilter(new CallableNameFilter($this->cache_name_function));
    1329         }
     1424        if ($function === null) {
     1425            $function = 'md5';
     1426        }
     1427
     1428        $this->cache_name_function = $function;
     1429
     1430        $this->set_cache_namefilter(new CallableNameFilter($this->cache_name_function));
    13301431    }
    13311432
     
    13371438     *
    13381439     * @param bool $set Whether to set them or not
    1339      */
    1340     public function set_stupidly_fast($set = false)
     1440     * @return void
     1441     */
     1442    public function set_stupidly_fast(bool $set = false)
    13411443    {
    13421444        if ($set) {
     
    13441446            $this->remove_div(false);
    13451447            $this->strip_comments(false);
    1346             $this->strip_htmltags(false);
    1347             $this->strip_attributes(false);
    1348             $this->add_attributes(false);
     1448            $this->strip_htmltags([]);
     1449            $this->strip_attributes([]);
     1450            $this->add_attributes([]);
    13491451            $this->set_image_handler(false);
    13501452            $this->set_https_domains([]);
     
    13561458     *
    13571459     * @param int $max Maximum number of feeds to check
    1358      */
    1359     public function set_max_checked_feeds($max = 10)
    1360     {
    1361         $this->max_checked_feeds = (int) $max;
    1362     }
    1363 
    1364     public function remove_div($enable = true)
     1460     * @return void
     1461     */
     1462    public function set_max_checked_feeds(int $max = 10)
     1463    {
     1464        $this->max_checked_feeds = $max;
     1465    }
     1466
     1467    /**
     1468     * @return void
     1469     */
     1470    public function remove_div(bool $enable = true)
    13651471    {
    13661472        $this->sanitize->remove_div($enable);
    13671473    }
    13681474
    1369     public function strip_htmltags($tags = '', $encode = null)
     1475    /**
     1476     * @param string[]|string|false $tags Set a list of tags to strip, or set empty string to use default tags, or false to strip nothing.
     1477     * @return void
     1478     */
     1479    public function strip_htmltags($tags = '', ?bool $encode = null)
    13701480    {
    13711481        if ($tags === '') {
     
    13781488    }
    13791489
    1380     public function encode_instead_of_strip($enable = true)
     1490    /**
     1491     * @return void
     1492     */
     1493    public function encode_instead_of_strip(bool $enable = true)
    13811494    {
    13821495        $this->sanitize->encode_instead_of_strip($enable);
    13831496    }
    13841497
     1498    /**
     1499     * @param string[]|string $attribs
     1500     * @return void
     1501     */
    13851502    public function rename_attributes($attribs = '')
    13861503    {
     
    13911508    }
    13921509
     1510    /**
     1511     * @param string[]|string $attribs
     1512     * @return void
     1513     */
    13931514    public function strip_attributes($attribs = '')
    13941515    {
     
    13991520    }
    14001521
     1522    /**
     1523     * @param array<string, array<string, string>>|'' $attribs
     1524     * @return void
     1525     */
    14011526    public function add_attributes($attribs = '')
    14021527    {
     
    14281553     *
    14291554     * @param string $encoding
    1430      */
    1431     public function set_output_encoding($encoding = 'UTF-8')
     1555     * @return void
     1556     */
     1557    public function set_output_encoding(string $encoding = 'UTF-8')
    14321558    {
    14331559        $this->sanitize->set_output_encoding($encoding);
    14341560    }
    14351561
    1436     public function strip_comments($strip = false)
     1562    /**
     1563     * @return void
     1564     */
     1565    public function strip_comments(bool $strip = false)
    14371566    {
    14381567        $this->sanitize->strip_comments($strip);
     
    14481577     *
    14491578     * @since 1.0
    1450      * @param array|null $element_attribute Element/attribute key/value pairs, null for default
    1451      */
    1452     public function set_url_replacements($element_attribute = null)
     1579     * @param array<string, string|string[]>|null $element_attribute Element/attribute key/value pairs, null for default
     1580     * @return void
     1581     */
     1582    public function set_url_replacements(?array $element_attribute = null)
    14531583    {
    14541584        $this->sanitize->set_url_replacements($element_attribute);
     
    14571587    /**
    14581588     * Set the list of domains for which to force HTTPS.
    1459      * @see \SimplePie\Sanitize::set_https_domains()
    1460      * @param array List of HTTPS domains. Example array('biz', 'example.com', 'example.org', 'www.example.net').
    1461      */
    1462     public function set_https_domains($domains = [])
    1463     {
    1464         if (is_array($domains)) {
    1465             $this->sanitize->set_https_domains($domains);
    1466         }
     1589     * @see Sanitize::set_https_domains()
     1590     * @param array<string> $domains List of HTTPS domains. Example array('biz', 'example.com', 'example.org', 'www.example.net').
     1591     * @return void
     1592     */
     1593    public function set_https_domains(array $domains = [])
     1594    {
     1595        $this->sanitize->set_https_domains($domains);
    14671596    }
    14681597
     
    14701599     * Set the handler to enable the display of cached images.
    14711600     *
    1472      * @param string $page Web-accessible path to the handler_image.php file.
     1601     * @param string|false $page Web-accessible path to the handler_image.php file.
    14731602     * @param string $qs The query string that the value should be passed to.
    1474      */
    1475     public function set_image_handler($page = false, $qs = 'i')
     1603     * @return void
     1604     */
     1605    public function set_image_handler($page = false, string $qs = 'i')
    14761606    {
    14771607        if ($page !== false) {
     
    14851615     * Set the limit for items returned per-feed with multifeeds
    14861616     *
    1487      * @param integer $limit The maximum number of items to return.
    1488      */
    1489     public function set_item_limit($limit = 0)
    1490     {
    1491         $this->item_limit = (int) $limit;
     1617     * @param int $limit The maximum number of items to return.
     1618     * @return void
     1619     */
     1620    public function set_item_limit(int $limit = 0)
     1621    {
     1622        $this->item_limit = $limit;
    14921623    }
    14931624
     
    14951626     * Enable throwing exceptions
    14961627     *
    1497      * @param boolean $enable Should we throw exceptions, or use the old-style error property?
    1498      */
    1499     public function enable_exceptions($enable = true)
     1628     * @param bool $enable Should we throw exceptions, or use the old-style error property?
     1629     * @return void
     1630     */
     1631    public function enable_exceptions(bool $enable = true)
    15001632    {
    15011633        $this->enable_exceptions = $enable;
     
    15091641     * parsed, and all of that other good stuff.
    15101642     *
    1511      * @return boolean True if successful, false otherwise
     1643     * @return bool True if successful, false otherwise
    15121644     */
    15131645    public function init()
     
    15241656                $parser_check = xml_parser_create();
    15251657                xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
    1526                 xml_parser_free($parser_check);
     1658                if (\PHP_VERSION_ID < 80000) {
     1659                    xml_parser_free($parser_check);
     1660                }
    15271661                $xml_is_sane = isset($values[0]['value']);
    15281662            }
     
    15341668        // The default sanitize class gets set in the constructor, check if it has
    15351669        // changed.
    1536         if ($this->registry->get_class(Sanitize::class) !== 'SimplePie\Sanitize') {
     1670        if ($this->registry->get_class(Sanitize::class) !== Sanitize::class) {
    15371671            $this->sanitize = $this->registry->create(Sanitize::class);
    15381672        }
     
    15431677        // Pass whatever was set with config options over to the sanitizer.
    15441678        // Pass the classes in for legacy support; new classes should use the registry instead
     1679        $cache = $this->registry->get_class(Cache::class);
     1680        \assert($cache !== null, 'Cache must be defined');
    15451681        $this->sanitize->pass_cache_data(
    15461682            $this->enable_cache,
    15471683            $this->cache_location,
    15481684            $this->cache_namefilter,
    1549             $this->registry->get_class(Cache::class),
     1685            $cache,
    15501686            $this->cache
    15511687        );
    1552         $this->sanitize->pass_file_data($this->registry->get_class(File::class), $this->timeout, $this->useragent, $this->force_fsockopen, $this->curl_options);
     1688
     1689        $http_client = $this->get_http_client();
     1690
     1691        if ($http_client instanceof Psr18Client) {
     1692            $this->sanitize->set_http_client(
     1693                $http_client->getHttpClient(),
     1694                $http_client->getRequestFactory(),
     1695                $http_client->getUriFactory()
     1696            );
     1697        }
    15531698
    15541699        if (!empty($this->multifeed_url)) {
     
    15861731            }
    15871732
    1588             // Fetch the data via \SimplePie\File into $this->raw_data
     1733            // Fetch the data into $this->raw_data
    15891734            if (($fetched = $this->fetch_data($cache)) === true) {
    15901735                return true;
     
    16501795
    16511796                // If it's parsed fine
    1652                 if ($parser->parse($utf8_data, 'UTF-8', $this->permanent_url)) {
     1797                if ($parser->parse($utf8_data, 'UTF-8', $this->permanent_url ?? '')) {
    16531798                    $this->data = $parser->get_data();
    16541799                    if (!($this->get_type() & ~self::TYPE_NONE)) {
     
    16611806                        $this->data['headers'] = $headers;
    16621807                    }
    1663                     $this->data['build'] = \SimplePie\Misc::get_build();
     1808                    $this->data['build'] = Misc::get_build();
    16641809
    16651810                    // Cache the file if caching is enabled
    16661811                    $this->data['cache_expiration_time'] = $this->cache_duration + time();
     1812
    16671813                    if ($cache && !$cache->set_data($this->get_cache_filename($this->feed_url), $this->data, $this->cache_duration)) {
    16681814                        trigger_error("$this->cache_location is not writable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
     
    16741820
    16751821        if (isset($parser)) {
    1676             // We have an error, just set \SimplePie\Misc::error to it and quit
     1822            // We have an error, just set Misc::error to it and quit
    16771823            $this->error = $this->feed_url;
    16781824            $this->error .= sprintf(' is invalid XML, likely due to invalid characters. XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column());
     
    17021848
    17031849    /**
    1704      * Fetch the data via \SimplePie\File
     1850     * Fetch the data
    17051851     *
    17061852     * If the data is already cached, attempt to fetch it from there instead
     1853     *
    17071854     * @param Base|DataCache|false $cache Cache handler, or false to not load from the cache
    1708      * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type
     1855     * @return array{array<string, string>, string}|bool Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type
    17091856     */
    17101857    protected function fetch_data(&$cache)
    17111858    {
    1712         if (is_object($cache) && $cache instanceof Base) {
     1859        if ($cache instanceof Base) {
    17131860            // @trigger_error(sprintf('Providing $cache as "\SimplePie\Cache\Base" in %s() is deprecated since SimplePie 1.8.0, please provide "\SimplePie\Cache\DataCache" implementation instead.', __METHOD__), \E_USER_DEPRECATED);
    17141861            $cache = new BaseDataCache($cache);
    17151862        }
    17161863
     1864        // @phpstan-ignore-next-line Enforce PHPDoc type.
    17171865        if ($cache !== false && !$cache instanceof DataCache) {
    17181866            throw new InvalidArgumentException(sprintf(
     
    17321880            if (!empty($this->data)) {
    17331881                // If the cache is for an outdated build of SimplePie
    1734                 if (!isset($this->data['build']) || $this->data['build'] !== \SimplePie\Misc::get_build()) {
     1882                if (!isset($this->data['build']) || $this->data['build'] !== Misc::get_build()) {
    17351883                    $cache->delete_data($cacheKey);
    17361884                    $this->data = [];
     
    17641912                    if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag'])) {
    17651913                        $headers = [
    1766                             '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',
     1914                            'Accept' => SimplePie::DEFAULT_HTTP_ACCEPT_HEADER,
    17671915                        ];
    17681916                        if (isset($this->data['headers']['last-modified'])) {
     
    17731921                        }
    17741922
    1775                         $file = $this->registry->create(File::class, [$this->feed_url, $this->timeout / 10, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options]);
    1776                         $this->status_code = $file->status_code;
    1777 
    1778                         if ($file->success) {
    1779                             if ($file->status_code === 304) {
    1780                                 // Set raw_data to false here too, to signify that the cache
    1781                                 // is still valid.
    1782                                 $this->raw_data = false;
     1923                        try {
     1924                            $file = $this->get_http_client()->request(Client::METHOD_GET, $this->feed_url, $headers);
     1925                            $this->status_code = $file->get_status_code();
     1926                        } catch (ClientException $th) {
     1927                            $this->check_modified = false;
     1928                            $this->status_code = 0;
     1929
     1930                            if ($this->force_cache_fallback) {
     1931                                $this->data['cache_expiration_time'] = $this->cache_duration + time();
    17831932                                $cache->set_data($cacheKey, $this->data, $this->cache_duration);
     1933
    17841934                                return true;
    17851935                            }
    1786                         } else {
    1787                             $this->check_modified = false;
    1788                             if ($this->force_cache_fallback) {
    1789                                 $cache->set_data($cacheKey, $this->data, $this->cache_duration);
    1790                                 return true;
    1791                             }
    1792 
    1793                             unset($file);
     1936
     1937                            $failedFileReason = $th->getMessage();
     1938                        }
     1939
     1940                        if ($this->status_code === 304) {
     1941                            // Set raw_data to false here too, to signify that the cache
     1942                            // is still valid.
     1943                            $this->raw_data = false;
     1944                            $this->data['cache_expiration_time'] = $this->cache_duration + time();
     1945                            $cache->set_data($cacheKey, $this->data, $this->cache_duration);
     1946
     1947                            return true;
    17941948                        }
    17951949                    }
     
    18091963        // If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it.
    18101964        if (!isset($file)) {
    1811             if ($this->file instanceof \SimplePie\File && $this->file->url === $this->feed_url) {
     1965            if ($this->file instanceof File && $this->file->get_final_requested_uri() === $this->feed_url) {
    18121966                $file = &$this->file;
     1967            } elseif (isset($failedFileReason)) {
     1968                // Do not try to fetch again if we already failed once.
     1969                // If the file connection had an error, set SimplePie::error to that and quit
     1970                $this->error = $failedFileReason;
     1971
     1972                return !empty($this->data);
    18131973            } else {
    18141974                $headers = [
    1815                     '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',
     1975                    'Accept' => SimplePie::DEFAULT_HTTP_ACCEPT_HEADER,
    18161976                ];
    1817                 $file = $this->registry->create(File::class, [$this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options]);
    1818             }
    1819         }
    1820         $this->status_code = $file->status_code;
     1977                try {
     1978                    $file = $this->get_http_client()->request(Client::METHOD_GET, $this->feed_url, $headers);
     1979                } catch (ClientException $th) {
     1980                    // If the file connection has an error, set SimplePie::error to that and quit
     1981                    $this->error = $th->getMessage();
     1982
     1983                    return !empty($this->data);
     1984                }
     1985            }
     1986        }
     1987        $this->status_code = $file->get_status_code();
    18211988
    18221989        // If the file connection has an error, set SimplePie::error to that and quit
    1823         if (!$file->success && !($file->method & self::FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300))) {
    1824             $this->error = $file->error;
     1990        if (!(!Misc::is_remote_uri($file->get_final_requested_uri()) || ($file->get_status_code() === 200 || $file->get_status_code() > 206 && $file->get_status_code() < 300))) {
     1991            $this->error = 'Retrieved unsupported status code "' . $this->status_code . '"';
    18251992            return !empty($this->data);
    18261993        }
     
    18281995        if (!$this->force_feed) {
    18291996            // Check if the supplied URL is a feed, if it isn't, look for it.
    1830             $locate = $this->registry->create(Locator::class, [&$file, $this->timeout, $this->useragent, $this->max_checked_feeds, $this->force_fsockopen, $this->curl_options]);
     1997            $locate = $this->registry->create(Locator::class, [
     1998                (!$file instanceof File) ? File::fromResponse($file) : $file,
     1999                $this->timeout,
     2000                $this->useragent,
     2001                $this->max_checked_feeds,
     2002                $this->force_fsockopen,
     2003                $this->curl_options
     2004            ]);
     2005
     2006            $http_client = $this->get_http_client();
     2007
     2008            if ($http_client instanceof Psr18Client) {
     2009                $locate->set_http_client(
     2010                    $http_client->getHttpClient(),
     2011                    $http_client->getRequestFactory(),
     2012                    $http_client->getUriFactory()
     2013                );
     2014            }
    18312015
    18322016            if (!$locate->is_feed($file)) {
    1833                 $copyStatusCode = $file->status_code;
    1834                 $copyContentType = $file->headers['content-type'] ?? '';
     2017                $copyStatusCode = $file->get_status_code();
     2018                $copyContentType = $file->get_header_line('content-type');
    18352019                try {
    18362020                    $microformats = false;
    18372021                    if (class_exists('DOMXpath') && function_exists('Mf2\parse')) {
    18382022                        $doc = new \DOMDocument();
    1839                         @$doc->loadHTML($file->body);
     2023                        @$doc->loadHTML($file->get_body_content());
    18402024                        $xpath = new \DOMXpath($doc);
    18412025                        // Check for both h-feed and h-entry, as both a feed with no entries
     
    18432027                        $query = '//*[contains(concat(" ", @class, " "), " h-feed ") or '.
    18442028                            'contains(concat(" ", @class, " "), " h-entry ")]';
     2029
     2030                        /** @var \DOMNodeList<\DOMElement> $result */
    18452031                        $result = $xpath->query($query);
    18462032                        $microformats = $result->length !== 0;
     
    18532039                    );
    18542040                    if ($microformats) {
    1855                         if ($hub = $locate->get_rel_link('hub')) {
    1856                             $self = $locate->get_rel_link('self');
    1857                             $this->store_links($file, $hub, $self);
     2041                        $hub = $locate->get_rel_link('hub');
     2042                        $self = $locate->get_rel_link('self');
     2043                        if ($hub || $self) {
     2044                            $file = $this->store_links($file, $hub, $self);
    18582045                        }
    18592046                        // Push the current file onto all_discovered feeds so the user can
    18602047                        // be shown this as one of the options.
    1861                         if (isset($this->all_discovered_feeds)) {
     2048                        if ($this->all_discovered_feeds !== null) {
    18622049                            $this->all_discovered_feeds[] = $file;
    18632050                        }
     
    18742061                        }
    18752062                    }
    1876                 } catch (\SimplePie\Exception $e) {
     2063                } catch (SimplePieException $e) {
    18772064                    // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
    18782065                    unset($file);
     
    18862073                    $this->data = [
    18872074                        'url' => $this->feed_url,
    1888                         'feed_url' => $file->url,
    1889                         'build' => \SimplePie\Misc::get_build(),
     2075                        'feed_url' => $file->get_final_requested_uri(),
     2076                        'build' => Misc::get_build(),
    18902077                        'cache_expiration_time' => $this->cache_duration + time(),
    18912078                    ];
     
    18962083                }
    18972084            }
    1898             $this->feed_url = $file->url;
     2085            $this->feed_url = $file->get_final_requested_uri();
    18992086            $locate = null;
    19002087        }
    19012088
    1902         $this->raw_data = $file->body;
    1903         $this->permanent_url = $file->permanent_url;
    1904         $headers = $file->headers;
     2089        $this->raw_data = $file->get_body_content();
     2090        $this->permanent_url = $file->get_permanent_uri();
     2091
     2092        $headers = [];
     2093        foreach ($file->get_headers() as $key => $values) {
     2094            $headers[$key] = implode(', ', $values);
     2095        }
     2096
    19052097        $sniffer = $this->registry->create(Sniffer::class, [&$file]);
    19062098        $sniffed = $sniffer->get_type();
     
    19122104     * Get the error message for the occurred error
    19132105     *
    1914      * @return string|array Error message, or array of messages for multifeeds
     2106     * @return string|string[]|null Error message, or array of messages for multifeeds
    19152107     */
    19162108    public function error()
     
    19352127     * the data instead of printing it.
    19362128     *
    1937      * @return string|boolean Raw XML data, false if the cache is used
     2129     * @return string|false Raw XML data, false if the cache is used
    19382130     */
    19392131    public function get_raw_data()
     
    19712163     *
    19722164     * @param string $mime MIME type to serve the page as
    1973      */
    1974     public function handle_content_type($mime = 'text/html')
     2165     * @return void
     2166     */
     2167    public function handle_content_type(string $mime = 'text/html')
    19752168    {
    19762169        if (!headers_sent()) {
     
    19882181     * Get the type of the feed
    19892182     *
    1990      * This returns a \SimplePie\SimplePie::TYPE_* constant, which can be tested against
     2183     * This returns a self::TYPE_* constant, which can be tested against
    19912184     * using {@link http://php.net/language.operators.bitwise bitwise operators}
    19922185     *
    19932186     * @since 0.8 (usage changed to using constants in 1.0)
    1994      * @see \SimplePie\SimplePie::TYPE_NONE Unknown.
    1995      * @see \SimplePie\SimplePie::TYPE_RSS_090 RSS 0.90.
    1996      * @see \SimplePie\SimplePie::TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape).
    1997      * @see \SimplePie\SimplePie::TYPE_RSS_091_USERLAND RSS 0.91 (Userland).
    1998      * @see \SimplePie\SimplePie::TYPE_RSS_091 RSS 0.91.
    1999      * @see \SimplePie\SimplePie::TYPE_RSS_092 RSS 0.92.
    2000      * @see \SimplePie\SimplePie::TYPE_RSS_093 RSS 0.93.
    2001      * @see \SimplePie\SimplePie::TYPE_RSS_094 RSS 0.94.
    2002      * @see \SimplePie\SimplePie::TYPE_RSS_10 RSS 1.0.
    2003      * @see \SimplePie\SimplePie::TYPE_RSS_20 RSS 2.0.x.
    2004      * @see \SimplePie\SimplePie::TYPE_RSS_RDF RDF-based RSS.
    2005      * @see \SimplePie\SimplePie::TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format).
    2006      * @see \SimplePie\SimplePie::TYPE_RSS_ALL Any version of RSS.
    2007      * @see \SimplePie\SimplePie::TYPE_ATOM_03 Atom 0.3.
    2008      * @see \SimplePie\SimplePie::TYPE_ATOM_10 Atom 1.0.
    2009      * @see \SimplePie\SimplePie::TYPE_ATOM_ALL Any version of Atom.
    2010      * @see \SimplePie\SimplePie::TYPE_ALL Any known/supported feed type.
    2011      * @return int \SimplePie\SimplePie::TYPE_* constant
     2187     * @see self::TYPE_NONE Unknown.
     2188     * @see self::TYPE_RSS_090 RSS 0.90.
     2189     * @see self::TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape).
     2190     * @see self::TYPE_RSS_091_USERLAND RSS 0.91 (Userland).
     2191     * @see self::TYPE_RSS_091 RSS 0.91.
     2192     * @see self::TYPE_RSS_092 RSS 0.92.
     2193     * @see self::TYPE_RSS_093 RSS 0.93.
     2194     * @see self::TYPE_RSS_094 RSS 0.94.
     2195     * @see self::TYPE_RSS_10 RSS 1.0.
     2196     * @see self::TYPE_RSS_20 RSS 2.0.x.
     2197     * @see self::TYPE_RSS_RDF RDF-based RSS.
     2198     * @see self::TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format).
     2199     * @see self::TYPE_RSS_ALL Any version of RSS.
     2200     * @see self::TYPE_ATOM_03 Atom 0.3.
     2201     * @see self::TYPE_ATOM_10 Atom 1.0.
     2202     * @see self::TYPE_ATOM_ALL Any version of Atom.
     2203     * @see self::TYPE_ALL Any known/supported feed type.
     2204     * @return int-mask-of<self::TYPE_*> constant
    20122205     */
    20132206    public function get_type()
     
    20942287     * @return string|null
    20952288     */
    2096     public function subscribe_url($permanent = false)
     2289    public function subscribe_url(bool $permanent = false)
    20972290    {
    20982291        if ($permanent) {
     
    21522345     * @param string $namespace The URL of the XML namespace of the elements you're trying to access
    21532346     * @param string $tag Tag name
    2154      * @return array
    2155      */
    2156     public function get_feed_tags($namespace, $tag)
     2347     * @return array<array<string, mixed>>|null
     2348     */
     2349    public function get_feed_tags(string $namespace, string $tag)
    21572350    {
    21582351        $type = $this->get_type();
     
    21922385     * @param string $namespace The URL of the XML namespace of the elements you're trying to access
    21932386     * @param string $tag Tag name
    2194      * @return array
    2195      */
    2196     public function get_channel_tags($namespace, $tag)
     2387     * @return array<array<string, mixed>>|null
     2388     */
     2389    public function get_channel_tags(string $namespace, string $tag)
    21972390    {
    21982391        $type = $this->get_type();
     
    22382431     * @param string $namespace The URL of the XML namespace of the elements you're trying to access
    22392432     * @param string $tag Tag name
    2240      * @return array
    2241      */
    2242     public function get_image_tags($namespace, $tag)
     2433     * @return array<array<string, mixed>>|null
     2434     */
     2435    public function get_image_tags(string $namespace, string $tag)
    22432436    {
    22442437        $type = $this->get_type();
     
    22702463     * Get the base URL value from the feed
    22712464     *
    2272      * Uses `<xml:base>` if available, otherwise uses the first link in the
    2273      * feed, or failing that, the URL of the feed itself.
     2465     * Uses `<xml:base>` if available,
     2466     * otherwise uses the first 'self' link or the first 'alternate' link of the feed,
     2467     * or failing that, the URL of the feed itself.
    22742468     *
    22752469     * @see get_link
    22762470     * @see subscribe_url
    22772471     *
    2278      * @param array $element
     2472     * @param array<string, mixed> $element
    22792473     * @return string
    22802474     */
    2281     public function get_base($element = [])
     2475    public function get_base(array $element = [])
    22822476    {
    22832477        if (!empty($element['xml_base_explicit']) && isset($element['xml_base'])) {
    22842478            return $element['xml_base'];
    2285         } elseif ($this->get_link() !== null) {
    2286             return $this->get_link();
    2287         }
    2288 
    2289         return $this->subscribe_url();
     2479        }
     2480        if (($link = $this->get_link(0, 'alternate')) !== null) {
     2481            return $link;
     2482        }
     2483        if (($link = $this->get_link(0, 'self')) !== null) {
     2484            return $link;
     2485        }
     2486
     2487        return $this->subscribe_url() ?? '';
    22902488    }
    22912489
     
    22942492     *
    22952493     * @access private
    2296      * @see \SimplePie\Sanitize::sanitize()
     2494     * @see Sanitize::sanitize()
    22972495     * @param string $data Data to sanitize
    2298      * @param int $type One of the \SimplePie\SimplePie::CONSTRUCT_* constants
     2496     * @param int-mask-of<SimplePie::CONSTRUCT_*> $type
    22992497     * @param string $base Base URL to resolve URLs against
    23002498     * @return string Sanitized data
    23012499     */
    2302     public function sanitize($data, $type, $base = '')
     2500    public function sanitize(string $data, int $type, string $base = '')
    23032501    {
    23042502        try {
     2503            // This really returns string|false but changing encoding is uncommon and we are going to deprecate it, so let’s just lie to PHPStan in the interest of cleaner annotations.
    23052504            return $this->sanitize->sanitize($data, $type, $base);
    2306         } catch (\SimplePie\Exception $e) {
     2505        } catch (SimplePieException $e) {
    23072506            if (!$this->enable_exceptions) {
    23082507                $this->error = $e->getMessage();
     
    23492548     * @since Unknown
    23502549     * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
    2351      * @return \SimplePie\Category|null
    2352      */
    2353     public function get_category($key = 0)
     2550     * @return Category|null
     2551     */
     2552    public function get_category(int $key = 0)
    23542553    {
    23552554        $categories = $this->get_categories();
     
    23672566     *
    23682567     * @since Unknown
    2369      * @return array|null List of {@see \SimplePie\Category} objects
     2568     * @return array<Category>|null List of {@see Category} objects
    23702569     */
    23712570    public function get_categories()
     
    24182617     * @since 1.1
    24192618     * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
    2420      * @return \SimplePie\Author|null
    2421      */
    2422     public function get_author($key = 0)
     2619     * @return Author|null
     2620     */
     2621    public function get_author(int $key = 0)
    24232622    {
    24242623        $authors = $this->get_authors();
     
    24362635     *
    24372636     * @since 1.1
    2438      * @return array|null List of {@see \SimplePie\Author} objects
     2637     * @return array<Author>|null List of {@see Author} objects
    24392638     */
    24402639    public function get_authors()
     
    24492648            }
    24502649            if (isset($author['child'][self::NAMESPACE_ATOM_10]['uri'][0]['data'])) {
    2451                 $uri = $this->sanitize($author['child'][self::NAMESPACE_ATOM_10]['uri'][0]['data'], self::CONSTRUCT_IRI, $this->get_base($author['child'][self::NAMESPACE_ATOM_10]['uri'][0]));
     2650                $uri = $author['child'][self::NAMESPACE_ATOM_10]['uri'][0];
     2651                $uri = $this->sanitize($uri['data'], self::CONSTRUCT_IRI, $this->get_base($uri));
    24522652            }
    24532653            if (isset($author['child'][self::NAMESPACE_ATOM_10]['email'][0]['data'])) {
     
    24662666            }
    24672667            if (isset($author[0]['child'][self::NAMESPACE_ATOM_03]['url'][0]['data'])) {
    2468                 $url = $this->sanitize($author[0]['child'][self::NAMESPACE_ATOM_03]['url'][0]['data'], self::CONSTRUCT_IRI, $this->get_base($author[0]['child'][self::NAMESPACE_ATOM_03]['url'][0]));
     2668                $url = $author[0]['child'][self::NAMESPACE_ATOM_03]['url'][0];
     2669                $url = $this->sanitize($url['data'], self::CONSTRUCT_IRI, $this->get_base($url));
    24692670            }
    24702671            if (isset($author[0]['child'][self::NAMESPACE_ATOM_03]['email'][0]['data'])) {
     
    24972698     * @since 1.1
    24982699     * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
    2499      * @return \SimplePie\Author|null
    2500      */
    2501     public function get_contributor($key = 0)
     2700     * @return Author|null
     2701     */
     2702    public function get_contributor(int $key = 0)
    25022703    {
    25032704        $contributors = $this->get_contributors();
     
    25152716     *
    25162717     * @since 1.1
    2517      * @return array|null List of {@see \SimplePie\Author} objects
     2718     * @return array<Author>|null List of {@see Author} objects
    25182719     */
    25192720    public function get_contributors()
     
    25282729            }
    25292730            if (isset($contributor['child'][self::NAMESPACE_ATOM_10]['uri'][0]['data'])) {
    2530                 $uri = $this->sanitize($contributor['child'][self::NAMESPACE_ATOM_10]['uri'][0]['data'], self::CONSTRUCT_IRI, $this->get_base($contributor['child'][self::NAMESPACE_ATOM_10]['uri'][0]));
     2731                $uri = $contributor['child'][self::NAMESPACE_ATOM_10]['uri'][0];
     2732                $uri = $this->sanitize($uri['data'], self::CONSTRUCT_IRI, $this->get_base($uri));
    25312733            }
    25322734            if (isset($contributor['child'][self::NAMESPACE_ATOM_10]['email'][0]['data'])) {
     
    25452747            }
    25462748            if (isset($contributor['child'][self::NAMESPACE_ATOM_03]['url'][0]['data'])) {
    2547                 $url = $this->sanitize($contributor['child'][self::NAMESPACE_ATOM_03]['url'][0]['data'], self::CONSTRUCT_IRI, $this->get_base($contributor['child'][self::NAMESPACE_ATOM_03]['url'][0]));
     2749                $url = $contributor['child'][self::NAMESPACE_ATOM_03]['url'][0];
     2750                $url = $this->sanitize($url['data'], self::CONSTRUCT_IRI, $this->get_base($url));
    25482751            }
    25492752            if (isset($contributor['child'][self::NAMESPACE_ATOM_03]['email'][0]['data'])) {
     
    25702773     * @return string|null Link URL
    25712774     */
    2572     public function get_link($key = 0, $rel = 'alternate')
     2775    public function get_link(int $key = 0, string $rel = 'alternate')
    25732776    {
    25742777        $links = $this->get_links($rel);
     
    26032806     * @since Beta 2
    26042807     * @param string $rel The relationship of links to return
    2605      * @return array|null Links found for the feed (strings)
    2606      */
    2607     public function get_links($rel = 'alternate')
     2808     * @return array<string>|null Links found for the feed (strings)
     2809     */
     2810    public function get_links(string $rel = 'alternate')
    26082811    {
    26092812        if (!isset($this->data['links'])) {
     
    26702873    }
    26712874
     2875    /**
     2876     * @return ?array<Response>
     2877     */
    26722878    public function get_all_discovered_feeds()
    26732879    {
     
    27732979     * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
    27742980     * @link http://www.georss.org/ GeoRSS
    2775      * @return string|null
     2981     * @return float|null
    27762982     */
    27772983    public function get_latitude()
     
    27963002     * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
    27973003     * @link http://www.georss.org/ GeoRSS
    2798      * @return string|null
     3004     * @return float|null
    27993005     */
    28003006    public function get_longitude()
     
    29433149     * @return int Number of items in the feed
    29443150     */
    2945     public function get_item_quantity($max = 0)
    2946     {
    2947         $max = (int) $max;
     3151    public function get_item_quantity(int $max = 0)
     3152    {
    29483153        $qty = count($this->get_items());
    29493154        if ($max === 0) {
     
    29513156        }
    29523157
    2953         return ($qty > $max) ? $max : $qty;
     3158        return min($qty, $max);
    29543159    }
    29553160
     
    29643169     * @since Beta 2
    29653170     * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1
    2966      * @return \SimplePie\Item|null
    2967      */
    2968     public function get_item($key = 0)
     3171     * @return Item|null
     3172     */
     3173    public function get_item(int $key = 0)
    29693174    {
    29703175        $items = $this->get_items();
     
    29873192     * @param int $start Index to start at
    29883193     * @param int $end Number of items to return. 0 for all items after `$start`
    2989      * @return \SimplePie\Item[]|null List of {@see \SimplePie\Item} objects
    2990      */
    2991     public function get_items($start = 0, $end = 0)
     3194     * @return Item[] List of {@see Item} objects
     3195     */
     3196    public function get_items(int $start = 0, int $end = 0)
    29923197    {
    29933198        if (!isset($this->data['items'])) {
     
    30033208                $keys = array_keys($items);
    30043209                foreach ($keys as $key) {
    3005                     $this->data['items'][] = $this->registry->create(Item::class, [$this, $items[$key]]);
     3210                    $this->data['items'][] = $this->make_item($items[$key]);
    30063211                }
    30073212            }
     
    30093214                $keys = array_keys($items);
    30103215                foreach ($keys as $key) {
    3011                     $this->data['items'][] = $this->registry->create(Item::class, [$this, $items[$key]]);
     3216                    $this->data['items'][] = $this->make_item($items[$key]);
    30123217                }
    30133218            }
     
    30153220                $keys = array_keys($items);
    30163221                foreach ($keys as $key) {
    3017                     $this->data['items'][] = $this->registry->create(Item::class, [$this, $items[$key]]);
     3222                    $this->data['items'][] = $this->make_item($items[$key]);
    30183223                }
    30193224            }
     
    30213226                $keys = array_keys($items);
    30223227                foreach ($keys as $key) {
    3023                     $this->data['items'][] = $this->registry->create(Item::class, [$this, $items[$key]]);
     3228                    $this->data['items'][] = $this->make_item($items[$key]);
    30243229                }
    30253230            }
     
    30273232                $keys = array_keys($items);
    30283233                foreach ($keys as $key) {
    3029                     $this->data['items'][] = $this->registry->create(Item::class, [$this, $items[$key]]);
     3234                    $this->data['items'][] = $this->make_item($items[$key]);
    30303235                }
    30313236            }
     
    30573262     *
    30583263     * @deprecated Use your own favicon handling instead
    3059      */
    3060     public function set_favicon_handler($page = false, $qs = 'i')
    3061     {
    3062         trigger_error('Favicon handling has been removed, please use your own handling', \E_USER_DEPRECATED);
     3264     * @param string|false $page
     3265     * @return bool
     3266     */
     3267    public function set_favicon_handler($page = false, string $qs = 'i')
     3268    {
     3269        trigger_error('Favicon handling has been removed since SimplePie 1.3, please use your own handling', \E_USER_DEPRECATED);
    30633270        return false;
    30643271    }
     
    30683275     *
    30693276     * @deprecated Use your own favicon handling instead
     3277     * @return string|bool
    30703278     */
    30713279    public function get_favicon()
    30723280    {
    3073         trigger_error('Favicon handling has been removed, please use your own handling', \E_USER_DEPRECATED);
     3281        trigger_error('Favicon handling has been removed since SimplePie 1.3, please use your own handling', \E_USER_DEPRECATED);
    30743282
    30753283        if (($url = $this->get_link()) !== null) {
     
    30843292     *
    30853293     * @param string $method Method name
    3086      * @param array $args Arguments to the method
     3294     * @param array<mixed> $args Arguments to the method
    30873295     * @return mixed
    30883296     */
    3089     public function __call($method, $args)
     3297    public function __call(string $method, array $args)
    30903298    {
    30913299        if (strpos($method, 'subscribe_') === 0) {
    3092             trigger_error('subscribe_*() has been deprecated, implement the callback yourself', \E_USER_DEPRECATED);
     3300            trigger_error('subscribe_*() has been deprecated since SimplePie 1.3, implement the callback yourself', \E_USER_DEPRECATED);
    30933301            return '';
    30943302        }
    30953303        if ($method === 'enable_xml_dump') {
    3096             trigger_error('enable_xml_dump() has been deprecated, use get_raw_data() instead', \E_USER_DEPRECATED);
     3304            trigger_error('enable_xml_dump() has been deprecated since SimplePie 1.3, use get_raw_data() instead', \E_USER_DEPRECATED);
    30973305            return false;
    30983306        }
     
    31003308        $class = get_class($this);
    31013309        $trace = debug_backtrace(); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
    3102         $file = $trace[0]['file'];
    3103         $line = $trace[0]['line'];
     3310        $file = $trace[0]['file'] ?? '';
     3311        $line = $trace[0]['line'] ?? '';
    31043312        throw new SimplePieException("Call to undefined method $class::$method() in $file on line $line");
    31053313    }
    31063314
    31073315    /**
     3316     * Item factory
     3317     *
     3318     * @param array<string, mixed> $data
     3319     */
     3320    private function make_item(array $data): Item
     3321    {
     3322        $item = $this->registry->create(Item::class, [$this, $data]);
     3323        $item->set_sanitize($this->sanitize);
     3324
     3325        return $item;
     3326    }
     3327
     3328    /**
    31083329     * Sorting callback for items
    31093330     *
    31103331     * @access private
    3111      * @param SimplePie $a
    3112      * @param SimplePie $b
    3113      * @return boolean
    3114      */
    3115     public static function sort_items($a, $b)
     3332     * @param Item $a
     3333     * @param Item $b
     3334     * @return -1|0|1
     3335     */
     3336    public static function sort_items(Item $a, Item $b)
    31163337    {
    31173338        $a_date = $a->get_date('U');
     
    31373358     *
    31383359     * @link http://simplepie.org/wiki/tutorial/sort_multiple_feeds_by_time_and_date#if_feeds_require_separate_per-feed_settings
    3139      * @param array $urls List of SimplePie feed objects to merge
     3360     * @param array<SimplePie> $urls List of SimplePie feed objects to merge
    31403361     * @param int $start Starting item
    31413362     * @param int $end Number of items to return
    31423363     * @param int $limit Maximum number of items per feed
    3143      * @return array
    3144      */
    3145     public static function merge_items($urls, $start = 0, $end = 0, $limit = 0)
    3146     {
    3147         if (is_array($urls) && sizeof($urls) > 0) {
     3364     * @return array<Item>
     3365     */
     3366    public static function merge_items(array $urls, int $start = 0, int $end = 0, int $limit = 0)
     3367    {
     3368        if (count($urls) > 0) {
    31483369            $items = [];
    31493370            foreach ($urls as $arg) {
    31503371                if ($arg instanceof SimplePie) {
    31513372                    $items = array_merge($items, $arg->get_items(0, $limit));
     3373
     3374                    // @phpstan-ignore-next-line Enforce PHPDoc type.
    31523375                } else {
    31533376                    trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
     
    31733396     * There is no way to find PuSH links in the body of a microformats feed,
    31743397     * so they are added to the headers when found, to be used later by get_links.
    3175      * @param \SimplePie\File $file
    3176      * @param string $hub
    3177      * @param string $self
    3178      */
    3179     private function store_links(&$file, $hub, $self)
    3180     {
    3181         if (isset($file->headers['link']['hub']) ||
    3182               (isset($file->headers['link']) &&
    3183                preg_match('/rel=hub/', $file->headers['link']))) {
    3184             return;
    3185         }
    3186 
    3187         if ($hub) {
    3188             if (isset($file->headers['link'])) {
    3189                 if ($file->headers['link'] !== '') {
    3190                     $file->headers['link'] = ', ';
    3191                 }
    3192             } else {
    3193                 $file->headers['link'] = '';
    3194             }
    3195             $file->headers['link'] .= '<'.$hub.'>; rel=hub';
    3196             if ($self) {
    3197                 $file->headers['link'] .= ', <'.$self.'>; rel=self';
    3198             }
    3199         }
     3398     */
     3399    private function store_links(Response $file, ?string $hub, ?string $self): Response
     3400    {
     3401        $linkHeaderLine = $file->get_header_line('link');
     3402        $linkHeader = $file->get_header('link');
     3403
     3404        if ($hub && !preg_match('/rel=hub/', $linkHeaderLine)) {
     3405            $linkHeader[] = '<'.$hub.'>; rel=hub';
     3406        }
     3407
     3408        if ($self && !preg_match('/rel=self/', $linkHeaderLine)) {
     3409            $linkHeader[] = '<'.$self.'>; rel=self';
     3410        }
     3411
     3412        if (count($linkHeader) > 0) {
     3413            $file = $file->with_header('link', $linkHeader);
     3414        }
     3415
     3416        return $file;
    32003417    }
    32013418
     
    32073424     * @return DataCache
    32083425     */
    3209     private function get_cache($feed_url = '')
     3426    private function get_cache(string $feed_url = ''): DataCache
    32103427    {
    32113428        if ($this->cache === null) {
     
    32223439        return $this->cache;
    32233440    }
     3441
     3442    /**
     3443     * Get a HTTP client
     3444     */
     3445    private function get_http_client(): Client
     3446    {
     3447        if ($this->http_client === null) {
     3448            $this->http_client = new FileClient(
     3449                $this->get_registry(),
     3450                [
     3451                    'timeout' => $this->timeout,
     3452                    'redirects' => 5,
     3453                    'useragent' => $this->useragent,
     3454                    'force_fsockopen' => $this->force_fsockopen,
     3455                    'curl_options' => $this->curl_options,
     3456                ]
     3457            );
     3458            $this->http_client_injected = true;
     3459        }
     3460
     3461        return $this->http_client;
     3462    }
    32243463}
    32253464
Note: See TracChangeset for help on using the changeset viewer.