diff --git a/core/modules/filter/src/Plugin/Filter/FilterHtml.php b/core/modules/filter/src/Plugin/Filter/FilterHtml.php index 6682f51..38d798a 100644 --- a/core/modules/filter/src/Plugin/Filter/FilterHtml.php +++ b/core/modules/filter/src/Plugin/Filter/FilterHtml.php @@ -131,37 +131,10 @@ public function filterAttributes($text) { } krsort($allowed_attributes['prefix']); - // Find all nodes that have any attributes and filter the attributes by - // name and value. - foreach ($xpath->query('//' . $allowed_tag . '[@*]') as $node) { - $modified_attributes = []; - foreach($node->attributes as $name => $attribute) { - // Remove attributes not in the whitelist. - $allowed_value = $this->findAllowedValue($allowed_attributes, $name); - if (empty($allowed_value)) { - $modified_attributes[$name] = FALSE; - } - elseif ($allowed_value !== TRUE) { - // Check the attribute values whitelist. - $attribute_values = preg_split('/\s+/', $attribute->value, -1, PREG_SPLIT_NO_EMPTY); - $modified_attributes[$name] = []; - foreach ($attribute_values as $value) { - if ($this->findAllowedValue($allowed_value, $value)) { - $modified_attributes[$name][] = $value; - } - } - } - } - // If the $allowed_value was TRUE for an attribute name, it does not - // appear in this array so the value on the DOM node is left unchanged. - foreach ($modified_attributes as $name => $values) { - if ($values) { - $node->setAttribute($name, implode(' ', $values)); - } - else { - $node->removeAttribute($name); - } - } + // Find all matching elements that have any attributes and filter the + // attributes by name and value. + foreach ($xpath->query('//' . $allowed_tag . '[@*]') as $element) { + $this->filterElementAttributes($element, $allowed_attributes); } } @@ -177,6 +150,45 @@ public function filterAttributes($text) { } /** + * Filter attributes on an element by name and value according to a whitelist. + * + * @param \DOMElement $element + * The element to be processed. + * @param array $allowed_attributes + * The attributes whitelist as an array of names and values. + */ + protected function filterElementAttributes(\DOMElement $element, array $allowed_attributes) { + $modified_attributes = []; + foreach($element->attributes as $name => $attribute) { + // Remove attributes not in the whitelist. + $allowed_value = $this->findAllowedValue($allowed_attributes, $name); + if (empty($allowed_value)) { + $modified_attributes[$name] = FALSE; + } + elseif ($allowed_value !== TRUE) { + // Check the attribute values whitelist. + $attribute_values = preg_split('/\s+/', $attribute->value, -1, PREG_SPLIT_NO_EMPTY); + $modified_attributes[$name] = []; + foreach ($attribute_values as $value) { + if ($this->findAllowedValue($allowed_value, $value)) { + $modified_attributes[$name][] = $value; + } + } + } + } + // If the $allowed_value was TRUE for an attribute name, it does not + // appear in this array so the value on the DOM element is left unchanged. + foreach ($modified_attributes as $name => $values) { + if ($values) { + $element->setAttribute($name, implode(' ', $values)); + } + else { + $element->removeAttribute($name); + } + } + } + + /** * Helper function to handle prefix matching. * * @param array $allowed @@ -256,6 +268,8 @@ public function getHTMLRestrictions() { } $tag = $node->tagName; if ($node->hasAttributes()) { + // Mark the tag as allowed, assigning TRUE for each attribute name if + // all values are allowed, or an array of specific allowed values. $restrictions['allowed'][$tag] = []; // Iterate over any attributes, and mark them as allowed. foreach ($node->attributes as $name => $attribute) {