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/Sanitize.php

    r59141 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
     10use DOMDocument;
     11use DOMXPath;
    4712use InvalidArgumentException;
     13use Psr\Http\Client\ClientInterface;
     14use Psr\Http\Message\RequestFactoryInterface;
     15use Psr\Http\Message\UriFactoryInterface;
    4816use SimplePie\Cache\Base;
    4917use SimplePie\Cache\BaseDataCache;
     
    5119use SimplePie\Cache\DataCache;
    5220use SimplePie\Cache\NameFilter;
     21use SimplePie\HTTP\Client;
     22use SimplePie\HTTP\ClientException;
     23use SimplePie\HTTP\FileClient;
     24use SimplePie\HTTP\Psr18Client;
    5325
    5426/**
     
    5830 * This class can be overloaded with {@see \SimplePie\SimplePie::set_sanitize_class()}
    5931 *
    60  * @package SimplePie
    6132 * @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags
    6233 */
     
    6435{
    6536    // Private vars
    66     public $base;
     37    /** @var string */
     38    public $base = '';
    6739
    6840    // Options
     41    /** @var bool */
    6942    public $remove_div = true;
     43    /** @var string */
    7044    public $image_handler = '';
     45    /** @var string[] */
    7146    public $strip_htmltags = ['base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'];
     47    /** @var bool */
    7248    public $encode_instead_of_strip = false;
     49    /** @var string[] */
    7350    public $strip_attributes = ['bgsound', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'];
     51    /** @var string[] */
    7452    public $rename_attributes = [];
     53    /** @var array<string, array<string, string>> */
    7554    public $add_attributes = ['audio' => ['preload' => 'none'], 'iframe' => ['sandbox' => 'allow-scripts allow-same-origin'], 'video' => ['preload' => 'none']];
     55    /** @var bool */
    7656    public $strip_comments = false;
     57    /** @var string */
    7758    public $output_encoding = 'UTF-8';
     59    /** @var bool */
    7860    public $enable_cache = true;
     61    /** @var string */
    7962    public $cache_location = './cache';
     63    /** @var string&(callable(string): string) */
    8064    public $cache_name_function = 'md5';
    8165
     
    8468     */
    8569    private $cache_namefilter;
     70    /** @var int */
    8671    public $timeout = 10;
     72    /** @var string */
    8773    public $useragent = '';
     74    /** @var bool */
    8875    public $force_fsockopen = false;
    89     public $replace_url_attributes = null;
     76    /** @var array<string, string|string[]> */
     77    public $replace_url_attributes = [];
     78    /**
     79     * @var array<int, mixed> Custom curl options
     80     * @see SimplePie::set_curl_options()
     81     */
     82    private $curl_options = [];
     83
     84    /** @var Registry */
    9085    public $registry;
    9186
     
    105100     * Array is a tree split at DNS levels. Example:
    106101     * array('biz' => true, 'com' => array('example' => true), 'net' => array('example' => array('www' => true)))
     102     * @var true|array<string, true|array<string, true|array<string, array<string, true|array<string, true|array<string, true>>>>>>
    107103     */
    108104    public $https_domains = [];
     105
     106    /**
     107     * @var Client|null
     108     */
     109    private $http_client = null;
    109110
    110111    public function __construct()
     
    114115    }
    115116
    116     public function remove_div($enable = true)
     117    /**
     118     * @return void
     119     */
     120    public function remove_div(bool $enable = true)
    117121    {
    118122        $this->remove_div = (bool) $enable;
    119123    }
    120124
     125    /**
     126     * @param string|false $page
     127     * @return void
     128     */
    121129    public function set_image_handler($page = false)
    122130    {
     
    124132            $this->image_handler = (string) $page;
    125133        } else {
    126             $this->image_handler = false;
    127         }
    128     }
    129 
    130     public function set_registry(\SimplePie\Registry $registry)/* : void */
     134            $this->image_handler = '';
     135        }
     136    }
     137
     138    /**
     139     * @return void
     140     */
     141    public function set_registry(\SimplePie\Registry $registry)
    131142    {
    132143        $this->registry = $registry;
    133144    }
    134145
    135     public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie\Cache', ?DataCache $cache = null)
    136     {
    137         if (isset($enable_cache)) {
    138             $this->enable_cache = (bool) $enable_cache;
    139         }
     146    /**
     147     * @param (string&(callable(string): string))|NameFilter $cache_name_function
     148     * @param class-string<Cache> $cache_class
     149     * @return void
     150     */
     151    public function pass_cache_data(bool $enable_cache = true, string $cache_location = './cache', $cache_name_function = 'md5', string $cache_class = Cache::class, ?DataCache $cache = null)
     152    {
     153        $this->enable_cache = $enable_cache;
    140154
    141155        if ($cache_location) {
    142             $this->cache_location = (string) $cache_location;
    143         }
    144 
    145         if (!is_string($cache_name_function) && !is_object($cache_name_function) && !$cache_name_function instanceof NameFilter) {
     156            $this->cache_location = $cache_location;
     157        }
     158
     159        // @phpstan-ignore-next-line Enforce PHPDoc type.
     160        if (!is_string($cache_name_function) && !$cache_name_function instanceof NameFilter) {
    146161            throw new InvalidArgumentException(sprintf(
    147162                '%s(): Argument #3 ($cache_name_function) must be of type %s',
     
    154169        if (is_string($cache_name_function)) {
    155170            // trigger_error(sprintf('Providing $cache_name_function as string in "%s()" is deprecated since SimplePie 1.8.0, provide as "%s" instead.', __METHOD__, NameFilter::class), \E_USER_DEPRECATED);
    156             $this->cache_name_function = (string) $cache_name_function;
     171            $this->cache_name_function = $cache_name_function;
    157172
    158173            $cache_name_function = new CallableNameFilter($cache_name_function);
     
    166181    }
    167182
    168     public function pass_file_data($file_class = 'SimplePie\File', $timeout = 10, $useragent = '', $force_fsockopen = false)
    169     {
     183    /**
     184     * Set a PSR-18 client and PSR-17 factories
     185     *
     186     * Allows you to use your own HTTP client implementations.
     187     */
     188    final public function set_http_client(
     189        ClientInterface $http_client,
     190        RequestFactoryInterface $request_factory,
     191        UriFactoryInterface $uri_factory
     192    ): void {
     193        $this->http_client = new Psr18Client($http_client, $request_factory, $uri_factory);
     194    }
     195
     196    /**
     197     * @deprecated since SimplePie 1.9.0, use \SimplePie\Sanitize::set_http_client() instead.
     198     * @param class-string<File> $file_class
     199     * @param array<int, mixed> $curl_options
     200     * @return void
     201     */
     202    public function pass_file_data(string $file_class = File::class, int $timeout = 10, string $useragent = '', bool $force_fsockopen = false, array $curl_options = [])
     203    {
     204        // trigger_error(sprintf('SimplePie\Sanitize::pass_file_data() is deprecated since SimplePie 1.9.0, please use "SimplePie\Sanitize::set_http_client()" instead.'), \E_USER_DEPRECATED);
    170205        if ($timeout) {
    171             $this->timeout = (string) $timeout;
     206            $this->timeout = $timeout;
    172207        }
    173208
    174209        if ($useragent) {
    175             $this->useragent = (string) $useragent;
     210            $this->useragent = $useragent;
    176211        }
    177212
    178213        if ($force_fsockopen) {
    179             $this->force_fsockopen = (string) $force_fsockopen;
    180         }
    181     }
    182 
     214            $this->force_fsockopen = $force_fsockopen;
     215        }
     216
     217        $this->curl_options = $curl_options;
     218        // Invalidate the registered client.
     219        $this->http_client = null;
     220    }
     221
     222    /**
     223     * @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.
     224     * @return void
     225     */
    183226    public function strip_htmltags($tags = ['base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'])
    184227    {
     
    190233            }
    191234        } else {
    192             $this->strip_htmltags = false;
    193         }
    194     }
    195 
    196     public function encode_instead_of_strip($encode = false)
    197     {
    198         $this->encode_instead_of_strip = (bool) $encode;
    199     }
    200 
     235            $this->strip_htmltags = [];
     236        }
     237    }
     238
     239    /**
     240     * @return void
     241     */
     242    public function encode_instead_of_strip(bool $encode = false)
     243    {
     244        $this->encode_instead_of_strip = $encode;
     245    }
     246
     247    /**
     248     * @param string[]|string $attribs
     249     * @return void
     250     */
    201251    public function rename_attributes($attribs = [])
    202252    {
     
    208258            }
    209259        } else {
    210             $this->rename_attributes = false;
    211         }
    212     }
    213 
     260            $this->rename_attributes = [];
     261        }
     262    }
     263
     264    /**
     265     * @param string[]|string $attribs
     266     * @return void
     267     */
    214268    public function strip_attributes($attribs = ['bgsound', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'])
    215269    {
     
    221275            }
    222276        } else {
    223             $this->strip_attributes = false;
    224         }
    225     }
    226 
    227     public function add_attributes($attribs = ['audio' => ['preload' => 'none'], 'iframe' => ['sandbox' => 'allow-scripts allow-same-origin'], 'video' => ['preload' => 'none']])
    228     {
    229         if ($attribs) {
    230             if (is_array($attribs)) {
    231                 $this->add_attributes = $attribs;
    232             } else {
    233                 $this->add_attributes = explode(',', $attribs);
    234             }
    235         } else {
    236             $this->add_attributes = false;
    237         }
    238     }
    239 
    240     public function strip_comments($strip = false)
    241     {
    242         $this->strip_comments = (bool) $strip;
    243     }
    244 
    245     public function set_output_encoding($encoding = 'UTF-8')
    246     {
    247         $this->output_encoding = (string) $encoding;
     277            $this->strip_attributes = [];
     278        }
     279    }
     280
     281    /**
     282     * @param array<string, array<string, string>> $attribs
     283     * @return void
     284     */
     285    public function add_attributes(array $attribs = ['audio' => ['preload' => 'none'], 'iframe' => ['sandbox' => 'allow-scripts allow-same-origin'], 'video' => ['preload' => 'none']])
     286    {
     287        $this->add_attributes = $attribs;
     288    }
     289
     290    /**
     291     * @return void
     292     */
     293    public function strip_comments(bool $strip = false)
     294    {
     295        $this->strip_comments = $strip;
     296    }
     297
     298    /**
     299     * @return void
     300     */
     301    public function set_output_encoding(string $encoding = 'UTF-8')
     302    {
     303        $this->output_encoding = $encoding;
    248304    }
    249305
     
    257313     *
    258314     * @since 1.0
    259      * @param array|null $element_attribute Element/attribute key/value pairs, null for default
    260      */
    261     public function set_url_replacements($element_attribute = null)
     315     * @param array<string, string|string[]>|null $element_attribute Element/attribute key/value pairs, null for default
     316     * @return void
     317     */
     318    public function set_url_replacements(?array $element_attribute = null)
    262319    {
    263320        if ($element_attribute === null) {
     
    283340            ];
    284341        }
    285         $this->replace_url_attributes = (array) $element_attribute;
     342        $this->replace_url_attributes = $element_attribute;
    286343    }
    287344
     
    290347     * @see \SimplePie\Misc::https_url()
    291348     * Example array('biz', 'example.com', 'example.org', 'www.example.net');
    292      */
    293     public function set_https_domains($domains)
     349     *
     350     * @param string[] $domains list of domain names ['biz', 'example.com', 'example.org', 'www.example.net']
     351     *
     352     * @return void
     353     */
     354    public function set_https_domains(array $domains)
    294355    {
    295356        $this->https_domains = [];
     
    297358            $domain = trim($domain, ". \t\n\r\0\x0B");
    298359            $segments = array_reverse(explode('.', $domain));
     360            /** @var true|array<string, true|array<string, true|array<string, array<string, true|array<string, true|array<string, true>>>>>> */ // Needed for PHPStan.
    299361            $node = &$this->https_domains;
    300362            foreach ($segments as $segment) {//Build a tree
     
    313375    /**
    314376     * Check if the domain is in the list of forced HTTPS.
    315      */
    316     protected function is_https_domain($domain)
     377     *
     378     * @return bool
     379     */
     380    protected function is_https_domain(string $domain)
    317381    {
    318382        $domain = trim($domain, '. ');
     
    331395    /**
    332396     * Force HTTPS for selected Web sites.
    333      */
    334     public function https_url($url)
    335     {
    336         return (strtolower(substr($url, 0, 7)) === 'http://') &&
    337             $this->is_https_domain(parse_url($url, PHP_URL_HOST)) ?
    338             substr_replace($url, 's', 4, 0) : //Add the 's' to HTTPS
    339             $url;
    340     }
    341 
    342     public function sanitize($data, $type, $base = '')
     397     *
     398     * @return string
     399     */
     400    public function https_url(string $url)
     401    {
     402        return (
     403            strtolower(substr($url, 0, 7)) === 'http://'
     404            && ($parsed = parse_url($url, PHP_URL_HOST)) !== false // Malformed URL
     405            && $parsed !== null // Missing host
     406            && $this->is_https_domain($parsed) // Should be forced?
     407        ) ? substr_replace($url, 's', 4, 0) // Add the 's' to HTTPS
     408        : $url;
     409    }
     410
     411    /**
     412     * @param int-mask-of<SimplePie::CONSTRUCT_*> $type
     413     * @param string $base
     414     * @return string Sanitized data; false if output encoding is changed to something other than UTF-8 and conversion fails
     415     */
     416    public function sanitize(string $data, int $type, string $base = '')
    343417    {
    344418        $data = trim($data);
     
    363437                $document->encoding = 'UTF-8';
    364438
     439                // PHPStan seems to have trouble resolving int-mask because bitwise
     440                // operators are used when operators are used when passing this parameter.
     441                // https://github.com/phpstan/phpstan/issues/9384
     442                /** @var int-mask-of<SimplePie::CONSTRUCT_*> $type */
    365443                $data = $this->preprocess($data, $type);
    366444
    367                 set_error_handler(['SimplePie\Misc', 'silence_errors']);
     445                set_error_handler([Misc::class, 'silence_errors']);
    368446                $document->loadHTML($data);
    369447                restore_error_handler();
     
    373451                // Strip comments
    374452                if ($this->strip_comments) {
     453                    /** @var \DOMNodeList<\DOMComment> */
    375454                    $comments = $xpath->query('//comment()');
    376455
    377456                    foreach ($comments as $comment) {
    378                         $comment->parentNode->removeChild($comment);
     457                        $parentNode = $comment->parentNode;
     458                        assert($parentNode !== null, 'For PHPStan, comment must have a parent');
     459                        $parentNode->removeChild($comment);
    379460                    }
    380461                }
     
    382463                // Strip out HTML tags and attributes that might cause various security problems.
    383464                // Based on recommendations by Mark Pilgrim at:
    384                 // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
     465                // https://web.archive.org/web/20110902041826/http://diveintomark.org:80/archives/2003/06/12/how_to_consume_rss_safely
    385466                if ($this->strip_htmltags) {
    386467                    foreach ($this->strip_htmltags as $tag) {
     
    414495
    415496                // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
    416                 if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache) {
     497                if ($this->image_handler !== '' && $this->enable_cache) {
    417498                    $images = $document->getElementsByTagName('img');
    418499
     
    425506                                $img->setAttribute('src', $this->image_handler . $image_url);
    426507                            } else {
    427                                 $file = $this->registry->create(File::class, [$img->getAttribute('src'), $this->timeout, 5, ['X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']], $this->useragent, $this->force_fsockopen]);
    428                                 $headers = $file->headers;
    429 
    430                                 if ($file->success && ($file->method & \SimplePie\SimplePie::FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300))) {
    431                                     if ($cache->set_data($image_url, ['headers' => $file->headers, 'body' => $file->body], $this->cache_duration)) {
     508                                try {
     509                                    $file = $this->get_http_client()->request(
     510                                        Client::METHOD_GET,
     511                                        $img->getAttribute('src'),
     512                                        ['X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']]
     513                                    );
     514                                } catch (ClientException $th) {
     515                                    continue;
     516                                }
     517
     518                                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))) {
     519                                    if ($cache->set_data($image_url, ['headers' => $file->get_headers(), 'body' => $file->get_body_content()], $this->cache_duration)) {
    432520                                        $img->setAttribute('src', $this->image_handler . $image_url);
    433521                                    } else {
     
    441529
    442530                // Get content node
    443                 $div = $document->getElementsByTagName('body')->item(0)->firstChild;
     531                $div = null;
     532                if (($item = $document->getElementsByTagName('body')->item(0)) !== null) {
     533                    $div = $item->firstChild;
     534                }
    444535                // Finally, convert to a HTML string
    445                 $data = trim($document->saveHTML($div));
     536                $data = trim((string) $document->saveHTML($div));
    446537
    447538                if ($this->remove_div) {
    448539                    $data = preg_replace('/^<div' . \SimplePie\SimplePie::PCRE_XML_ATTRIBUTE . '>/', '', $data);
    449                     $data = preg_replace('/<\/div>$/', '', $data);
     540                    // Cast for PHPStan, it is unable to validate a non-literal regex above.
     541                    $data = preg_replace('/<\/div>$/', '', (string) $data);
    450542                } else {
    451543                    $data = preg_replace('/^<div' . \SimplePie\SimplePie::PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
    452544                }
    453545
    454                 $data = str_replace('</source>', '', $data);
     546                // Cast for PHPStan, it is unable to validate a non-literal regex above.
     547                $data = str_replace('</source>', '', (string) $data);
    455548            }
    456549
     
    467560
    468561            if ($this->output_encoding !== 'UTF-8') {
     562                // 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.
     563                /** @var string */
    469564                $data = $this->registry->call(Misc::class, 'change_encoding', [$data, 'UTF-8', $this->output_encoding]);
    470565            }
     
    473568    }
    474569
    475     protected function preprocess($html, $type)
     570    /**
     571     * @param int-mask-of<SimplePie::CONSTRUCT_*> $type
     572     * @return string
     573     */
     574    protected function preprocess(string $html, int $type)
    476575    {
    477576        $ret = '';
     
    494593    }
    495594
    496     public function replace_urls($document, $tag, $attributes)
     595    /**
     596     * @param array<string>|string $attributes
     597     * @return void
     598     */
     599    public function replace_urls(DOMDocument $document, string $tag, $attributes)
    497600    {
    498601        if (!is_array($attributes)) {
     
    516619    }
    517620
    518     public function do_strip_htmltags($match)
     621    /**
     622     * @param array<int, string> $match
     623     * @return string
     624     */
     625    public function do_strip_htmltags(array $match)
    519626    {
    520627        if ($this->encode_instead_of_strip) {
     
    533640    }
    534641
    535     protected function strip_tag($tag, $document, $xpath, $type)
     642    /**
     643     * @param int-mask-of<SimplePie::CONSTRUCT_*> $type
     644     * @return void
     645     */
     646    protected function strip_tag(string $tag, DOMDocument $document, DOMXPath $xpath, int $type)
    536647    {
    537648        $elements = $xpath->query('body//' . $tag);
     649
     650        if ($elements === false) {
     651            throw new \SimplePie\Exception(sprintf(
     652                '%s(): Possibly malformed expression, check argument #1 ($tag)',
     653                __METHOD__
     654            ), 1);
     655        }
     656
    538657        if ($this->encode_instead_of_strip) {
    539658            foreach ($elements as $element) {
     
    543662                if (!in_array($tag, ['script', 'style'])) {
    544663                    $text = '<' . $tag;
    545                     if ($element->hasAttributes()) {
     664                    if ($element->attributes !== null) {
    546665                        $attrs = [];
    547666                        foreach ($element->attributes as $name => $attr) {
     
    569688                $number = $element->childNodes->length;
    570689                for ($i = $number; $i > 0; $i--) {
    571                     $child = $element->childNodes->item(0);
    572                     $fragment->appendChild($child);
     690                    if (($child = $element->childNodes->item(0)) !== null) {
     691                        $fragment->appendChild($child);
     692                    }
    573693                }
    574694
     
    577697                }
    578698
    579                 $element->parentNode->replaceChild($fragment, $element);
     699                if (($parentNode = $element->parentNode) !== null) {
     700                    $parentNode->replaceChild($fragment, $element);
     701                }
    580702            }
    581703
     
    583705        } elseif (in_array($tag, ['script', 'style'])) {
    584706            foreach ($elements as $element) {
    585                 $element->parentNode->removeChild($element);
     707                if (($parentNode = $element->parentNode) !== null) {
     708                    $parentNode->removeChild($element);
     709                }
    586710            }
    587711
     
    592716                $number = $element->childNodes->length;
    593717                for ($i = $number; $i > 0; $i--) {
    594                     $child = $element->childNodes->item(0);
    595                     $fragment->appendChild($child);
    596                 }
    597 
    598                 $element->parentNode->replaceChild($fragment, $element);
    599             }
    600         }
    601     }
    602 
    603     protected function strip_attr($attrib, $xpath)
     718                    if (($child = $element->childNodes->item(0)) !== null) {
     719                        $fragment->appendChild($child);
     720                    }
     721                }
     722
     723                if (($parentNode = $element->parentNode) !== null) {
     724                    $parentNode->replaceChild($fragment, $element);
     725                }
     726            }
     727        }
     728    }
     729
     730    /**
     731     * @return void
     732     */
     733    protected function strip_attr(string $attrib, DOMXPath $xpath)
    604734    {
    605735        $elements = $xpath->query('//*[@' . $attrib . ']');
    606736
     737        if ($elements === false) {
     738            throw new \SimplePie\Exception(sprintf(
     739                '%s(): Possibly malformed expression, check argument #1 ($attrib)',
     740                __METHOD__
     741            ), 1);
     742        }
     743
     744        /** @var \DOMElement $element */
    607745        foreach ($elements as $element) {
    608746            $element->removeAttribute($attrib);
     
    610748    }
    611749
    612     protected function rename_attr($attrib, $xpath)
     750    /**
     751     * @return void
     752     */
     753    protected function rename_attr(string $attrib, DOMXPath $xpath)
    613754    {
    614755        $elements = $xpath->query('//*[@' . $attrib . ']');
    615756
     757        if ($elements === false) {
     758            throw new \SimplePie\Exception(sprintf(
     759                '%s(): Possibly malformed expression, check argument #1 ($attrib)',
     760                __METHOD__
     761            ), 1);
     762        }
     763
     764        /** @var \DOMElement $element */
    616765        foreach ($elements as $element) {
    617766            $element->setAttribute('data-sanitized-' . $attrib, $element->getAttribute($attrib));
     
    620769    }
    621770
    622     protected function add_attr($tag, $valuePairs, $document)
     771    /**
     772     * @param array<string, string> $valuePairs
     773     * @return void
     774     */
     775    protected function add_attr(string $tag, array $valuePairs, DOMDocument $document)
    623776    {
    624777        $elements = $document->getElementsByTagName($tag);
     778        /** @var \DOMElement $element */
    625779        foreach ($elements as $element) {
    626780            foreach ($valuePairs as $attrib => $value) {
     
    637791     * @return DataCache
    638792     */
    639     private function get_cache($image_url = '')
     793    private function get_cache(string $image_url = ''): DataCache
    640794    {
    641795        if ($this->cache === null) {
     
    652806        return $this->cache;
    653807    }
     808
     809    /**
     810     * Get a HTTP client
     811     */
     812    private function get_http_client(): Client
     813    {
     814        if ($this->http_client === null) {
     815            $this->http_client = new FileClient(
     816                $this->registry,
     817                [
     818                    'timeout' => $this->timeout,
     819                    'redirects' => 5,
     820                    'useragent' => $this->useragent,
     821                    'force_fsockopen' => $this->force_fsockopen,
     822                    'curl_options' => $this->curl_options,
     823                ]
     824            );
     825        }
     826
     827        return $this->http_client;
     828    }
    654829}
    655830
Note: See TracChangeset for help on using the changeset viewer.