Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
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
 */
44
 
45
namespace SimplePie;
46
 
47
use InvalidArgumentException;
48
use SimplePie\Cache\Base;
49
use SimplePie\Cache\BaseDataCache;
50
use SimplePie\Cache\CallableNameFilter;
51
use SimplePie\Cache\DataCache;
52
use SimplePie\Cache\NameFilter;
53
 
54
/**
55
 * Used for data cleanup and post-processing
56
 *
57
 *
58
 * This class can be overloaded with {@see \SimplePie\SimplePie::set_sanitize_class()}
59
 *
60
 * @package SimplePie
61
 * @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
62
 */
63
class Sanitize implements RegistryAware
64
{
65
    // Private vars
66
    public $base;
67
 
68
    // Options
69
    public $remove_div = true;
70
    public $image_handler = '';
71
    public $strip_htmltags = ['base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'];
72
    public $encode_instead_of_strip = false;
73
    public $strip_attributes = ['bgsound', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'];
74
    public $rename_attributes = [];
75
    public $add_attributes = ['audio' => ['preload' => 'none'], 'iframe' => ['sandbox' => 'allow-scripts allow-same-origin'], 'video' => ['preload' => 'none']];
76
    public $strip_comments = false;
77
    public $output_encoding = 'UTF-8';
78
    public $enable_cache = true;
79
    public $cache_location = './cache';
80
    public $cache_name_function = 'md5';
81
 
82
    /**
83
     * @var NameFilter
84
     */
85
    private $cache_namefilter;
86
    public $timeout = 10;
87
    public $useragent = '';
88
    public $force_fsockopen = false;
89
    public $replace_url_attributes = null;
90
    public $registry;
91
 
92
    /**
93
     * @var DataCache|null
94
     */
95
    private $cache = null;
96
 
97
    /**
98
     * @var int Cache duration (in seconds)
99
     */
100
    private $cache_duration = 3600;
101
 
102
    /**
103
     * List of domains for which to force HTTPS.
104
     * @see \SimplePie\Sanitize::set_https_domains()
105
     * Array is a tree split at DNS levels. Example:
106
     * array('biz' => true, 'com' => array('example' => true), 'net' => array('example' => array('www' => true)))
107
     */
108
    public $https_domains = [];
109
 
110
    public function __construct()
111
    {
112
        // Set defaults
113
        $this->set_url_replacements(null);
114
    }
115
 
116
    public function remove_div($enable = true)
117
    {
118
        $this->remove_div = (bool) $enable;
119
    }
120
 
121
    public function set_image_handler($page = false)
122
    {
123
        if ($page) {
124
            $this->image_handler = (string) $page;
125
        } else {
126
            $this->image_handler = false;
127
        }
128
    }
129
 
130
    public function set_registry(\SimplePie\Registry $registry)/* : void */
131
    {
132
        $this->registry = $registry;
133
    }
134
 
1441 ariadna 135
    public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie\Cache', ?DataCache $cache = null)
1 efrain 136
    {
137
        if (isset($enable_cache)) {
138
            $this->enable_cache = (bool) $enable_cache;
139
        }
140
 
141
        if ($cache_location) {
142
            $this->cache_location = (string) $cache_location;
143
        }
144
 
1441 ariadna 145
        if (!is_string($cache_name_function) && !is_object($cache_name_function) && !$cache_name_function instanceof NameFilter) {
1 efrain 146
            throw new InvalidArgumentException(sprintf(
147
                '%s(): Argument #3 ($cache_name_function) must be of type %s',
148
                __METHOD__,
149
                NameFilter::class
150
            ), 1);
151
        }
152
 
153
        // BC: $cache_name_function could be a callable as string
154
        if (is_string($cache_name_function)) {
155
            // 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;
157
 
158
            $cache_name_function = new CallableNameFilter($cache_name_function);
159
        }
160
 
161
        $this->cache_namefilter = $cache_name_function;
162
 
163
        if ($cache !== null) {
164
            $this->cache = $cache;
165
        }
166
    }
167
 
168
    public function pass_file_data($file_class = 'SimplePie\File', $timeout = 10, $useragent = '', $force_fsockopen = false)
169
    {
170
        if ($timeout) {
171
            $this->timeout = (string) $timeout;
172
        }
173
 
174
        if ($useragent) {
175
            $this->useragent = (string) $useragent;
176
        }
177
 
178
        if ($force_fsockopen) {
179
            $this->force_fsockopen = (string) $force_fsockopen;
180
        }
181
    }
182
 
183
    public function strip_htmltags($tags = ['base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'])
184
    {
185
        if ($tags) {
186
            if (is_array($tags)) {
187
                $this->strip_htmltags = $tags;
188
            } else {
189
                $this->strip_htmltags = explode(',', $tags);
190
            }
191
        } 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
 
201
    public function rename_attributes($attribs = [])
202
    {
203
        if ($attribs) {
204
            if (is_array($attribs)) {
205
                $this->rename_attributes = $attribs;
206
            } else {
207
                $this->rename_attributes = explode(',', $attribs);
208
            }
209
        } else {
210
            $this->rename_attributes = false;
211
        }
212
    }
213
 
214
    public function strip_attributes($attribs = ['bgsound', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'])
215
    {
216
        if ($attribs) {
217
            if (is_array($attribs)) {
218
                $this->strip_attributes = $attribs;
219
            } else {
220
                $this->strip_attributes = explode(',', $attribs);
221
            }
222
        } 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;
248
    }
249
 
250
    /**
251
     * Set element/attribute key/value pairs of HTML attributes
252
     * containing URLs that need to be resolved relative to the feed
253
     *
254
     * Defaults to |a|@href, |area|@href, |audio|@src, |blockquote|@cite,
255
     * |del|@cite, |form|@action, |img|@longdesc, |img|@src, |input|@src,
256
     * |ins|@cite, |q|@cite, |source|@src, |video|@src
257
     *
258
     * @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)
262
    {
263
        if ($element_attribute === null) {
264
            $element_attribute = [
265
                'a' => 'href',
266
                'area' => 'href',
267
                'audio' => 'src',
268
                'blockquote' => 'cite',
269
                'del' => 'cite',
270
                'form' => 'action',
271
                'img' => [
272
                    'longdesc',
273
                    'src'
274
                ],
275
                'input' => 'src',
276
                'ins' => 'cite',
277
                'q' => 'cite',
278
                'source' => 'src',
279
                'video' => [
280
                    'poster',
281
                    'src'
282
                ]
283
            ];
284
        }
285
        $this->replace_url_attributes = (array) $element_attribute;
286
    }
287
 
288
    /**
289
     * Set the list of domains for which to force HTTPS.
290
     * @see \SimplePie\Misc::https_url()
291
     * Example array('biz', 'example.com', 'example.org', 'www.example.net');
292
     */
293
    public function set_https_domains($domains)
294
    {
295
        $this->https_domains = [];
296
        foreach ($domains as $domain) {
297
            $domain = trim($domain, ". \t\n\r\0\x0B");
298
            $segments = array_reverse(explode('.', $domain));
1441 ariadna 299
            $node = &$this->https_domains;
1 efrain 300
            foreach ($segments as $segment) {//Build a tree
301
                if ($node === true) {
302
                    break;
303
                }
304
                if (!isset($node[$segment])) {
305
                    $node[$segment] = [];
306
                }
1441 ariadna 307
                $node = &$node[$segment];
1 efrain 308
            }
309
            $node = true;
310
        }
311
    }
312
 
313
    /**
314
     * Check if the domain is in the list of forced HTTPS.
315
     */
316
    protected function is_https_domain($domain)
317
    {
318
        $domain = trim($domain, '. ');
319
        $segments = array_reverse(explode('.', $domain));
1441 ariadna 320
        $node = &$this->https_domains;
1 efrain 321
        foreach ($segments as $segment) {//Explore the tree
322
            if (isset($node[$segment])) {
1441 ariadna 323
                $node = &$node[$segment];
1 efrain 324
            } else {
325
                break;
326
            }
327
        }
328
        return $node === true;
329
    }
330
 
331
    /**
332
     * 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 = '')
343
    {
344
        $data = trim($data);
345
        if ($data !== '' || $type & \SimplePie\SimplePie::CONSTRUCT_IRI) {
346
            if ($type & \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML) {
347
                if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . \SimplePie\SimplePie::PCRE_HTML_ATTRIBUTE . '>)/', $data)) {
348
                    $type |= \SimplePie\SimplePie::CONSTRUCT_HTML;
349
                } else {
350
                    $type |= \SimplePie\SimplePie::CONSTRUCT_TEXT;
351
                }
352
            }
353
 
354
            if ($type & \SimplePie\SimplePie::CONSTRUCT_BASE64) {
355
                $data = base64_decode($data);
356
            }
357
 
358
            if ($type & (\SimplePie\SimplePie::CONSTRUCT_HTML | \SimplePie\SimplePie::CONSTRUCT_XHTML)) {
359
                if (!class_exists('DOMDocument')) {
360
                    throw new \SimplePie\Exception('DOMDocument not found, unable to use sanitizer');
361
                }
362
                $document = new \DOMDocument();
363
                $document->encoding = 'UTF-8';
364
 
365
                $data = $this->preprocess($data, $type);
366
 
367
                set_error_handler(['SimplePie\Misc', 'silence_errors']);
368
                $document->loadHTML($data);
369
                restore_error_handler();
370
 
371
                $xpath = new \DOMXPath($document);
372
 
373
                // Strip comments
374
                if ($this->strip_comments) {
375
                    $comments = $xpath->query('//comment()');
376
 
377
                    foreach ($comments as $comment) {
378
                        $comment->parentNode->removeChild($comment);
379
                    }
380
                }
381
 
382
                // Strip out HTML tags and attributes that might cause various security problems.
383
                // Based on recommendations by Mark Pilgrim at:
384
                // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
385
                if ($this->strip_htmltags) {
386
                    foreach ($this->strip_htmltags as $tag) {
387
                        $this->strip_tag($tag, $document, $xpath, $type);
388
                    }
389
                }
390
 
391
                if ($this->rename_attributes) {
392
                    foreach ($this->rename_attributes as $attrib) {
393
                        $this->rename_attr($attrib, $xpath);
394
                    }
395
                }
396
 
397
                if ($this->strip_attributes) {
398
                    foreach ($this->strip_attributes as $attrib) {
399
                        $this->strip_attr($attrib, $xpath);
400
                    }
401
                }
402
 
403
                if ($this->add_attributes) {
404
                    foreach ($this->add_attributes as $tag => $valuePairs) {
405
                        $this->add_attr($tag, $valuePairs, $document);
406
                    }
407
                }
408
 
409
                // Replace relative URLs
410
                $this->base = $base;
411
                foreach ($this->replace_url_attributes as $element => $attributes) {
412
                    $this->replace_urls($document, $element, $attributes);
413
                }
414
 
415
                // 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) {
417
                    $images = $document->getElementsByTagName('img');
418
 
419
                    foreach ($images as $img) {
420
                        if ($img->hasAttribute('src')) {
421
                            $image_url = $this->cache_namefilter->filter($img->getAttribute('src'));
422
                            $cache = $this->get_cache($image_url);
423
 
424
                            if ($cache->get_data($image_url, false)) {
425
                                $img->setAttribute('src', $this->image_handler . $image_url);
426
                            } 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)) {
432
                                        $img->setAttribute('src', $this->image_handler . $image_url);
433
                                    } else {
434
                                        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);
435
                                    }
436
                                }
437
                            }
438
                        }
439
                    }
440
                }
441
 
442
                // Get content node
443
                $div = $document->getElementsByTagName('body')->item(0)->firstChild;
444
                // Finally, convert to a HTML string
445
                $data = trim($document->saveHTML($div));
446
 
447
                if ($this->remove_div) {
448
                    $data = preg_replace('/^<div' . \SimplePie\SimplePie::PCRE_XML_ATTRIBUTE . '>/', '', $data);
449
                    $data = preg_replace('/<\/div>$/', '', $data);
450
                } else {
451
                    $data = preg_replace('/^<div' . \SimplePie\SimplePie::PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
452
                }
453
 
454
                $data = str_replace('</source>', '', $data);
455
            }
456
 
457
            if ($type & \SimplePie\SimplePie::CONSTRUCT_IRI) {
458
                $absolute = $this->registry->call(Misc::class, 'absolutize_url', [$data, $base]);
459
                if ($absolute !== false) {
460
                    $data = $absolute;
461
                }
462
            }
463
 
464
            if ($type & (\SimplePie\SimplePie::CONSTRUCT_TEXT | \SimplePie\SimplePie::CONSTRUCT_IRI)) {
465
                $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
466
            }
467
 
468
            if ($this->output_encoding !== 'UTF-8') {
469
                $data = $this->registry->call(Misc::class, 'change_encoding', [$data, 'UTF-8', $this->output_encoding]);
470
            }
471
        }
472
        return $data;
473
    }
474
 
475
    protected function preprocess($html, $type)
476
    {
477
        $ret = '';
478
        $html = preg_replace('%</?(?:html|body)[^>]*?'.'>%is', '', $html);
479
        if ($type & ~\SimplePie\SimplePie::CONSTRUCT_XHTML) {
480
            // Atom XHTML constructs are wrapped with a div by default
481
            // Note: No protection if $html contains a stray </div>!
482
            $html = '<div>' . $html . '</div>';
483
            $ret .= '<!DOCTYPE html>';
484
            $content_type = 'text/html';
485
        } else {
486
            $ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
487
            $content_type = 'application/xhtml+xml';
488
        }
489
 
490
        $ret .= '<html><head>';
491
        $ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />';
492
        $ret .= '</head><body>' . $html . '</body></html>';
493
        return $ret;
494
    }
495
 
496
    public function replace_urls($document, $tag, $attributes)
497
    {
498
        if (!is_array($attributes)) {
499
            $attributes = [$attributes];
500
        }
501
 
502
        if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags)) {
503
            $elements = $document->getElementsByTagName($tag);
504
            foreach ($elements as $element) {
505
                foreach ($attributes as $attribute) {
506
                    if ($element->hasAttribute($attribute)) {
507
                        $value = $this->registry->call(Misc::class, 'absolutize_url', [$element->getAttribute($attribute), $this->base]);
508
                        if ($value !== false) {
509
                            $value = $this->https_url($value);
510
                            $element->setAttribute($attribute, $value);
511
                        }
512
                    }
513
                }
514
            }
515
        }
516
    }
517
 
518
    public function do_strip_htmltags($match)
519
    {
520
        if ($this->encode_instead_of_strip) {
521
            if (isset($match[4]) && !in_array(strtolower($match[1]), ['script', 'style'])) {
522
                $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
523
                $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
524
                return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
525
            } else {
526
                return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
527
            }
528
        } elseif (isset($match[4]) && !in_array(strtolower($match[1]), ['script', 'style'])) {
529
            return $match[4];
530
        } else {
531
            return '';
532
        }
533
    }
534
 
535
    protected function strip_tag($tag, $document, $xpath, $type)
536
    {
537
        $elements = $xpath->query('body//' . $tag);
538
        if ($this->encode_instead_of_strip) {
539
            foreach ($elements as $element) {
540
                $fragment = $document->createDocumentFragment();
541
 
542
                // For elements which aren't script or style, include the tag itself
543
                if (!in_array($tag, ['script', 'style'])) {
544
                    $text = '<' . $tag;
545
                    if ($element->hasAttributes()) {
546
                        $attrs = [];
547
                        foreach ($element->attributes as $name => $attr) {
548
                            $value = $attr->value;
549
 
550
                            // In XHTML, empty values should never exist, so we repeat the value
551
                            if (empty($value) && ($type & \SimplePie\SimplePie::CONSTRUCT_XHTML)) {
552
                                $value = $name;
553
                            }
554
                            // For HTML, empty is fine
555
                            elseif (empty($value) && ($type & \SimplePie\SimplePie::CONSTRUCT_HTML)) {
556
                                $attrs[] = $name;
557
                                continue;
558
                            }
559
 
560
                            // Standard attribute text
561
                            $attrs[] = $name . '="' . $attr->value . '"';
562
                        }
563
                        $text .= ' ' . implode(' ', $attrs);
564
                    }
565
                    $text .= '>';
566
                    $fragment->appendChild(new \DOMText($text));
567
                }
568
 
569
                $number = $element->childNodes->length;
570
                for ($i = $number; $i > 0; $i--) {
571
                    $child = $element->childNodes->item(0);
572
                    $fragment->appendChild($child);
573
                }
574
 
575
                if (!in_array($tag, ['script', 'style'])) {
576
                    $fragment->appendChild(new \DOMText('</' . $tag . '>'));
577
                }
578
 
579
                $element->parentNode->replaceChild($fragment, $element);
580
            }
581
 
582
            return;
583
        } elseif (in_array($tag, ['script', 'style'])) {
584
            foreach ($elements as $element) {
585
                $element->parentNode->removeChild($element);
586
            }
587
 
588
            return;
589
        } else {
590
            foreach ($elements as $element) {
591
                $fragment = $document->createDocumentFragment();
592
                $number = $element->childNodes->length;
593
                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)
604
    {
605
        $elements = $xpath->query('//*[@' . $attrib . ']');
606
 
607
        foreach ($elements as $element) {
608
            $element->removeAttribute($attrib);
609
        }
610
    }
611
 
612
    protected function rename_attr($attrib, $xpath)
613
    {
614
        $elements = $xpath->query('//*[@' . $attrib . ']');
615
 
616
        foreach ($elements as $element) {
617
            $element->setAttribute('data-sanitized-' . $attrib, $element->getAttribute($attrib));
618
            $element->removeAttribute($attrib);
619
        }
620
    }
621
 
622
    protected function add_attr($tag, $valuePairs, $document)
623
    {
624
        $elements = $document->getElementsByTagName($tag);
625
        foreach ($elements as $element) {
626
            foreach ($valuePairs as $attrib => $value) {
627
                $element->setAttribute($attrib, $value);
628
            }
629
        }
630
    }
631
 
632
    /**
633
     * Get a DataCache
634
     *
635
     * @param string $image_url Only needed for BC, can be removed in SimplePie 2.0.0
636
     *
637
     * @return DataCache
638
     */
639
    private function get_cache($image_url = '')
640
    {
641
        if ($this->cache === null) {
642
            // @trigger_error(sprintf('Not providing as PSR-16 cache implementation is deprecated since SimplePie 1.8.0, please use "SimplePie\SimplePie::set_cache()".'), \E_USER_DEPRECATED);
643
            $cache = $this->registry->call(Cache::class, 'get_handler', [
644
                $this->cache_location,
645
                $image_url,
646
                Base::TYPE_IMAGE
647
            ]);
648
 
649
            return new BaseDataCache($cache);
650
        }
651
 
652
        return $this->cache;
653
    }
654
}
655
 
656
class_alias('SimplePie\Sanitize', 'SimplePie_Sanitize');