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

		// Importing itself will ensure the XML is at least
		// vaguely valid. It will also adjust tag casing,
		// quote styles, etc.
		if (false === ($dom = static::import($svg))) {
			return false;
		}

		// Whitelist.
		$allowed_tags = static::get_allowed_tags();
		$allowed_attributes = static::get_allowed_attributes();
		$iri_attributes = static::get_iri_attributes();
		$xpath = new DOMXPath($dom);

		// Validate tags.
		$tags = $dom->getElementsByTagName('*');

		for ($x = $tags->length - 1; $x >= 0; $x--) {
			$tag = $tags->item($x);

			// @codingStandardsIgnoreStart
			$tag_name = mb::strtolower($tag->tagName);
			// @codingStandardsIgnoreEnd

			// 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)) {
				static::remove_node($tag);
				continue;
			}

			// If this is a <style> tag, we want to decode entities.
			// Thanks XML!
			if ('style' === $tag_name) {
				// @codingStandardsIgnoreStart
				$style = strip_tags(static::sanitize_attribute_value($tag->textContent));
				$tag->textContent = $style;
				// @codingStandardsIgnoreEnd
			}

			// Use XPath for attributes, as $tag->attributes will skip
			// anything namespaced. Note: We aren't focusing on
			// actual Namespaces here, that comes later.
			$attributes = $xpath->query('.//@*', $tag);
			for ($y = $attributes->length - 1; $y >= 0; $y--) {
				$attribute = $attributes->item($y);

				// @codingStandardsIgnoreStart
				$attribute_name = mb::strtolower($attribute->nodeName);
				// @codingStandardsIgnoreEnd

				// Could be namespaced.
				if (
					!in_array($attribute_name, $allowed_attributes, true) &&
					false !== ($start = mb::strpos($attribute_name, ':'))
				) {
					$attribute_name = mb::substr($attribute_name, $start + 1);
				}

				// Bad attribute: not whitelisted.
				// data-* is implicitly whitelisted.
				if (
					!preg_match('/^data\-/', $attribute_name) &&
					!in_array($attribute_name, $allowed_attributes, true)
				) {
					// @codingStandardsIgnoreStart
					$tag->removeAttribute($attribute->nodeName);
					// @codingStandardsIgnoreEnd
					continue;
				}

				// Validate values.
				$attribute_value = static::sanitize_attribute_value($attribute->value);

				// Validate protocols.
				// IRI attributes get the full KSES treatment.
				$iri = false;
				if (in_array($attribute_name, $iri_attributes, true)) {
					$iri = true;
					$attribute_value = static::sanitize_iri_value($attribute_value);
				} // For others, we are specifically interested in removing scripty bits.
				elseif (preg_match('/(?:\w+script):/xi', $attribute_value)) {
					$attribute_value = '';
				}

				// Update it.
				if ($attribute_value !== $attribute->value) {
					// @codingStandardsIgnoreStart
					if ($iri) {
						$tag->removeAttribute($attribute->nodeName);
					} else {
						$tag->setAttribute($attribute->nodeName, $attribute_value);
					}
					// @codingStandardsIgnoreEnd
				}
			}
		} // Each tag.

		// Once more through the tags to find namespaces.
		$tags = $dom->getElementsByTagName('*');
		for ($x = 0; $x < $tags->length; $x++) {
			$tag = $tags->item($x);
			$nodes = $xpath->query('namespace::*', $tag);
			for ($y = 0; $y < $nodes->length; $y++) {
				$node = $nodes->item($y);

				// @codingStandardsIgnoreStart
				$node_name = mb::strtolower($node->nodeName);
				// @codingStandardsIgnoreEnd

				// Not xmlns?
				if (!preg_match('/^xmlns:/', $node_name)) {
					// @codingStandardsIgnoreStart
					static::remove_namespace($dom, $node->localName);
					// @codingStandardsIgnoreEnd
					continue;
				}

				// Validate values.
				// @codingStandardsIgnoreStart
				$node_value = static::sanitize_attribute_value($node->nodeValue);
				// @codingStandardsIgnoreEnd
				$node_value = static::sanitize_iri_value($node_value);

				// Remove invalid.
				if (!strlen($node_value)) {
					// @codingStandardsIgnoreStart
					static::remove_namespace($dom, $node->localName);
					// @codingStandardsIgnoreEnd
				}
			}
		}

		// Back to a string!
		if (false === ($svg = static::export($dom))) {
			return false;
		}

		// Sanitize CSS values (e.g. foo="url(...)").
		$svg = preg_replace_callback('/url\s*\((.*)\s*\)/Ui', array(get_called_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);

		// 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);

		// Importing itself will ensure the XML is at least
		// vaguely valid. It will also adjust tag casing,
		// quote styles, etc.
		if (false === ($dom = static::import($svg))) {
			return false;
		}

		// Whitelist.
		$allowed_tags = static::get_allowed_tags();
		$allowed_attributes = static::get_allowed_attributes();
		$iri_attributes = static::get_iri_attributes();
		$xpath = new DOMXPath($dom);

		// Validate tags.
		$tags = $dom->getElementsByTagName('*');

		for ($x = $tags->length - 1; $x >= 0; $x--) {
			$tag = $tags->item($x);

			// @codingStandardsIgnoreStart
			$tag_name = mb::strtolower($tag->tagName);
			// @codingStandardsIgnoreEnd

			// 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)) {
				static::remove_node($tag);
				continue;
			}

			// If this is a <style> tag, we want to decode entities.
			// Thanks XML!
			if ('style' === $tag_name) {
				// @codingStandardsIgnoreStart
				$style = strip_tags(static::sanitize_attribute_value($tag->textContent));
				$tag->textContent = $style;
				// @codingStandardsIgnoreEnd
			}

			// Use XPath for attributes, as $tag->attributes will skip
			// anything namespaced. Note: We aren't focusing on
			// actual Namespaces here, that comes later.
			$attributes = $xpath->query('.//@*', $tag);
			for ($y = $attributes->length - 1; $y >= 0; $y--) {
				$attribute = $attributes->item($y);

				// @codingStandardsIgnoreStart
				$attribute_name = mb::strtolower($attribute->nodeName);
				// @codingStandardsIgnoreEnd

				// Could be namespaced.
				if (
					!in_array($attribute_name, $allowed_attributes, true) &&
					false !== ($start = mb::strpos($attribute_name, ':'))
				) {
					$attribute_name = mb::substr($attribute_name, $start + 1);
				}

				// Bad attribute: not whitelisted.
				// data-* is implicitly whitelisted.
				if (
					!preg_match('/^data\-/', $attribute_name) &&
					!in_array($attribute_name, $allowed_attributes, true)
				) {
					// @codingStandardsIgnoreStart
					$tag->removeAttribute($attribute->nodeName);
					// @codingStandardsIgnoreEnd
					continue;
				}

				// Validate values.
				$attribute_value = static::sanitize_attribute_value($attribute->value);

				// Validate protocols.
				// IRI attributes get the full KSES treatment.
				$iri = false;
				if (in_array($attribute_name, $iri_attributes, true)) {
					$iri = true;
					$attribute_value = static::sanitize_iri_value($attribute_value);
				} // For others, we are specifically interested in removing scripty bits.
				elseif (preg_match('/(?:\w+script):/xi', $attribute_value)) {
					$attribute_value = '';
				}

				// Update it.
				if ($attribute_value !== $attribute->value) {
					// @codingStandardsIgnoreStart
					if ($iri) {
						$tag->removeAttribute($attribute->nodeName);
					} else {
						$tag->setAttribute($attribute->nodeName, $attribute_value);
					}
					// @codingStandardsIgnoreEnd
				}
			}
		} // Each tag.

		// Once more through the tags to find namespaces.
		$tags = $dom->getElementsByTagName('*');
		for ($x = 0; $x < $tags->length; $x++) {
			$tag = $tags->item($x);
			$nodes = $xpath->query('namespace::*', $tag);
			for ($y = 0; $y < $nodes->length; $y++) {
				$node = $nodes->item($y);

				// @codingStandardsIgnoreStart
				$node_name = mb::strtolower($node->nodeName);
				// @codingStandardsIgnoreEnd

				// Not xmlns?
				if (!preg_match('/^xmlns:/', $node_name)) {
					// @codingStandardsIgnoreStart
					static::remove_namespace($dom, $node->localName);
					// @codingStandardsIgnoreEnd
					continue;
				}

				// Validate values.
				// @codingStandardsIgnoreStart
				$node_value = static::sanitize_attribute_value($node->nodeValue);
				// @codingStandardsIgnoreEnd
				$node_value = static::sanitize_iri_value($node_value);

				// Remove invalid.
				if (!strlen($node_value)) {
					// @codingStandardsIgnoreStart
					static::remove_namespace($dom, $node->localName);
					// @codingStandardsIgnoreEnd
				}
			}
		}

		// Back to a string!
		if (false === ($svg = static::export($dom))) {
			return false;
		}

		// Sanitize CSS values (e.g. foo="url(...)").
		$svg = preg_replace_callback('/url\s*\((.*)\s*\)/Ui', array(get_called_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);

		// 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. False on failure.