-
-
Notifications
You must be signed in to change notification settings - Fork 624
Expand file tree
/
Copy pathSvg.php
More file actions
61 lines (47 loc) · 1.95 KB
/
Svg.php
File metadata and controls
61 lines (47 loc) · 1.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?php
namespace Statamic\Support;
use Rhukster\DomSanitizer\DOMSanitizer;
use Stringy\StaticStringy;
class Svg
{
public static function withClasses(string $svg, ?string $classes = null): string
{
$attrs = " class=\"{$classes}\"";
$svg = StaticStringy::collapseWhitespace($svg);
return str_replace('<svg', sprintf('<svg%s', $attrs), $svg);
}
public static function sanitize(string $svg, ?DOMSanitizer $sanitizer = null): string
{
$sanitizer = $sanitizer ?? new DOMSanitizer(DOMSanitizer::SVG);
$svg = static::sanitizeStyleTags($svg);
return $sanitizer->sanitize($svg, [
'remove-xml-tags' => ! Str::startsWith($svg, '<?xml'),
]);
}
public static function sanitizeCss(string $css): string
{
// Decode all CSS escape sequences in a single pass to prevent bypass.
// Hex escapes: \69mport -> import. Non-hex escapes: \i -> i, \@ -> @.
$css = preg_replace_callback(
'/\\\\(?:([0-9a-fA-F]{1,6})\s?|(.))/s',
fn ($m) => ($m[1] !== '') ? mb_chr(hexdec($m[1]), 'UTF-8') : $m[2],
$css
);
// Normalize Unicode whitespace and invisible characters to ASCII spaces
// so they can't be used to sneak past the regex patterns below
$css = preg_replace('/[\p{Z}\x{200B}\x{FEFF}]+/u', ' ', $css);
// Remove @import rules entirely
$css = preg_replace('/@import\s+[^;]+;?/i', '', $css);
// Neutralize url() references to external resources (http, https, protocol-relative)
$css = preg_replace('/url\s*\(\s*["\']?\s*(?:https?:|\/\/)[^)]*\)/i', 'url()', $css);
return $css;
}
private static function sanitizeStyleTags(string $svg): string
{
return preg_replace_callback(
'/<style([^>]*)>(.*?)<\/style>/si',
fn ($matches) => '<style'.$matches[1].'>'.static::sanitizeCss($matches[2]).'</style>',
$svg
);
}
}