wp/lib/blobfolio/wp/bm/svg/svg_fallback.php
public static function sanitize($svg = '', $header=true) {
		$svg = \apply_filters('blobmimes_svg_pre_sanitize', $svg);

		if (false === $svg = static::import($svg)) {
			return false;
		}

		// Allowed.
		$allowed_tags = static::get_allowed_tags();

		// We'll need to clean up styles a bit later.
		$style_tags = array();

		// First, find and remove invalid tags and their contents.
		\preg_match_all('%(<[^>]*(>|$)|>)%', $svg, $matches);
		if (\count($matches[0])) {
			$invalid = array();
			foreach ($matches[0] as $raw) {
				// Ignore malformed.
				if (
					\substr($raw, 0, 1) !== '<' ||
					! \preg_match('%^<\s*(/\s*)?([a-zA-Z0-9-:]+)([^>]*)>?$%', $raw, $matches2)
				) {
					continue;
				}

				// Don't need closing tags now.
				if (\trim($matches2[1]) === '/') {
					continue;
				}

				$tag = mb::strtolower($matches2[2]);
				$tag_name = $tag;
				// The tag might be namespaced (ns:tag). We'll allow it if
				// the tag is allowed.
				if (
					false !== mb::strpos($tag_name, ':') &&
					! \in_array($tag_name, $allowed_tags, true)
				) {
					$tag_name = \explode(':', $tag_name);
					$tag_name = $tag_name[1];
				}

				// Bad tag: not whitelisted.
				if (! \in_array($tag_name, $allowed_tags, true)) {
					$invalid[] = $tag;
				} elseif ('style' === $tag_name) {
					$style_tags[] = $tag;
				}
			}

			// Actual removal.
			if (\count($invalid)) {
				$invalid = \array_unique($invalid);
				foreach ($invalid as $k=>$v) {
					$invalid[$k] = \preg_quote($v, '@');
				}

				// Remove open/close pairs.
				$svg = \preg_replace('@<(' . \implode('|', $invalid) . ')\b.*?>.*?</\1>@si', '', $svg);

				// Remove self-closing.
				$svg = \preg_replace('@<(' . \implode('|', $invalid) . ')\b.*?/>@si', '', $svg);
			}
		}

		// Similar to wp_kses_split(), however a separate
		// function was needed for proper XML support.
		$svg = \preg_replace_callback('%(<[^>]*(>|$)|>)%', array(static::class, 'split_tags'), $svg);

		// We need to decode entities in <style> tags.
		// Thanks XML!
		if (\count($style_tags)) {
			$style_tags = \array_unique($style_tags);
			foreach ($style_tags as $k=>$v) {
				$style_tags[$k] = \preg_quote($v, '@');
			}

			\preg_match_all('@<(' . \implode('|', $style_tags) . ')\b(.*?)>(.*?)</\1>@si', $svg, $matches2);
			if (\count($matches2[0])) {
				$replacements = array();
				foreach ($matches2[0] as $k=>$v) {
					// 0 Whole Match.
					// 1 Tag.
					// 2 Attributes.
					// 3 Contents.
					$replacements[$v] = "<{$matches2[1][$k]} {$matches2[2][$k]}>" .
						\strip_tags(static::sanitize_attribute_value($matches2[3][$k])) .
						"</{$matches2[1][$k]}>";
				}

				if (\count($replacements)) {
					$svg = \str_replace(\array_keys($replacements), \array_values($replacements), $svg);
				}
			}
		}

		// Remove comments.
		$svg = static::strip_comments($svg);

		// Sanitize CSS values (e.g. foo="url(...)").
		$svg = \preg_replace_callback('/url\s*\((.*)\s*\)/Ui', array(static::class, 'callback_sanitize_css_iri'), $svg);

		// Make sure if xmlns="" exists, it is correct. Can't alter
		// that with DOMDocument, and there is only one proper value.
		$svg = \preg_replace('/xmlns\s*=\s*"[^"]*"/', 'xmlns="' . static::XMLNS_NAMESPACE . '"', $svg);

		// Let's crunch some whitespace!
		$svg = \preg_replace('/\s+/u', ' ', $svg);
		$svg = \str_replace('> <', '><', $svg);

		if (
			false === ($start = mb::strpos($svg, '<svg')) ||
			false === ($end = mb::strrpos($svg, '</svg>'))
		) {
			return false;
		}

		// Add our headers, and we're done!
		if ($header) {
			$svg = static::XMLTAG . "\n" . static::get_doctype() . "\n$svg";
		}

		// Done!
		return \apply_filters('blobmimes_svg_post_sanitize', $svg);
	}
public static function sanitize($svg = '', $header=true) {
		$svg = \apply_filters('blobmimes_svg_pre_sanitize', $svg);

		if (false === $svg = static::import($svg)) {
			return false;
		}

		// Allowed.
		$allowed_tags = static::get_allowed_tags();

		// We'll need to clean up styles a bit later.
		$style_tags = array();

		// First, find and remove invalid tags and their contents.
		\preg_match_all('%(<[^>]*(>|$)|>)%', $svg, $matches);
		if (\count($matches[0])) {
			$invalid = array();
			foreach ($matches[0] as $raw) {
				// Ignore malformed.
				if (
					\substr($raw, 0, 1) !== '<' ||
					! \preg_match('%^<\s*(/\s*)?([a-zA-Z0-9-:]+)([^>]*)>?$%', $raw, $matches2)
				) {
					continue;
				}

				// Don't need closing tags now.
				if (\trim($matches2[1]) === '/') {
					continue;
				}

				$tag = mb::strtolower($matches2[2]);
				$tag_name = $tag;
				// The tag might be namespaced (ns:tag). We'll allow it if
				// the tag is allowed.
				if (
					false !== mb::strpos($tag_name, ':') &&
					! \in_array($tag_name, $allowed_tags, true)
				) {
					$tag_name = \explode(':', $tag_name);
					$tag_name = $tag_name[1];
				}

				// Bad tag: not whitelisted.
				if (! \in_array($tag_name, $allowed_tags, true)) {
					$invalid[] = $tag;
				} elseif ('style' === $tag_name) {
					$style_tags[] = $tag;
				}
			}

			// Actual removal.
			if (\count($invalid)) {
				$invalid = \array_unique($invalid);
				foreach ($invalid as $k=>$v) {
					$invalid[$k] = \preg_quote($v, '@');
				}

				// Remove open/close pairs.
				$svg = \preg_replace('@<(' . \implode('|', $invalid) . ')\b.*?>.*?</\1>@si', '', $svg);

				// Remove self-closing.
				$svg = \preg_replace('@<(' . \implode('|', $invalid) . ')\b.*?/>@si', '', $svg);
			}
		}

		// Similar to wp_kses_split(), however a separate
		// function was needed for proper XML support.
		$svg = \preg_replace_callback('%(<[^>]*(>|$)|>)%', array(static::class, 'split_tags'), $svg);

		// We need to decode entities in <style> tags.
		// Thanks XML!
		if (\count($style_tags)) {
			$style_tags = \array_unique($style_tags);
			foreach ($style_tags as $k=>$v) {
				$style_tags[$k] = \preg_quote($v, '@');
			}

			\preg_match_all('@<(' . \implode('|', $style_tags) . ')\b(.*?)>(.*?)</\1>@si', $svg, $matches2);
			if (\count($matches2[0])) {
				$replacements = array();
				foreach ($matches2[0] as $k=>$v) {
					// 0 Whole Match.
					// 1 Tag.
					// 2 Attributes.
					// 3 Contents.
					$replacements[$v] = "<{$matches2[1][$k]} {$matches2[2][$k]}>" .
						\strip_tags(static::sanitize_attribute_value($matches2[3][$k])) .
						"</{$matches2[1][$k]}>";
				}

				if (\count($replacements)) {
					$svg = \str_replace(\array_keys($replacements), \array_values($replacements), $svg);
				}
			}
		}

		// Remove comments.
		$svg = static::strip_comments($svg);

		// Sanitize CSS values (e.g. foo="url(...)").
		$svg = \preg_replace_callback('/url\s*\((.*)\s*\)/Ui', array(static::class, 'callback_sanitize_css_iri'), $svg);

		// Make sure if xmlns="" exists, it is correct. Can't alter
		// that with DOMDocument, and there is only one proper value.
		$svg = \preg_replace('/xmlns\s*=\s*"[^"]*"/', 'xmlns="' . static::XMLNS_NAMESPACE . '"', $svg);

		// Let's crunch some whitespace!
		$svg = \preg_replace('/\s+/u', ' ', $svg);
		$svg = \str_replace('> <', '><', $svg);

		if (
			false === ($start = mb::strpos($svg, '<svg')) ||
			false === ($end = mb::strrpos($svg, '</svg>'))
		) {
			return false;
		}

		// Add our headers, and we're done!
		if ($header) {
			$svg = static::XMLTAG . "\n" . static::get_doctype() . "\n$svg";
		}

		// Done!
		return \apply_filters('blobmimes_svg_post_sanitize', $svg);
	}
Sanitize an SVG

@param string $svg SVG code or path.
@param bool $header Append header.
@return string|bool Sanitized SVG code or false.