You are here

public function FilterHtml::filterAttributes in Drupal 8

Same name and namespace in other branches
  1. 9 core/modules/filter/src/Plugin/Filter/FilterHtml.php \Drupal\filter\Plugin\Filter\FilterHtml::filterAttributes()

Provides filtering of tag attributes into accepted HTML.

Parameters

string $text: The HTML text string to be filtered.

Return value

string Filtered HTML with attributes filtered according to the settings.

1 call to FilterHtml::filterAttributes()
FilterHtml::process in core/modules/filter/src/Plugin/Filter/FilterHtml.php
Performs the filter processing.

File

core/modules/filter/src/Plugin/Filter/FilterHtml.php, line 106

Class

FilterHtml
Provides a filter to limit allowed HTML tags.

Namespace

Drupal\filter\Plugin\Filter

Code

public function filterAttributes($text) {
  $restrictions = $this
    ->getHTMLRestrictions();
  $global_allowed_attributes = array_filter($restrictions['allowed']['*']);
  unset($restrictions['allowed']['*']);

  // Apply attribute restrictions to tags.
  $html_dom = Html::load($text);
  $xpath = new \DOMXPath($html_dom);
  foreach ($restrictions['allowed'] as $allowed_tag => $tag_attributes) {

    // By default, no attributes are allowed for a tag, but due to the
    // globally allowed attributes, it is impossible for a tag to actually
    // completely disallow attributes.
    if ($tag_attributes === FALSE) {
      $tag_attributes = [];
    }
    $allowed_attributes = [
      'exact' => [],
      'prefix' => [],
    ];
    foreach ($global_allowed_attributes + $tag_attributes as $name => $values) {

      // A trailing * indicates wildcard, but it must have some prefix.
      if (substr($name, -1) === '*' && $name[0] !== '*') {
        $allowed_attributes['prefix'][str_replace('*', '', $name)] = $this
          ->prepareAttributeValues($values);
      }
      else {
        $allowed_attributes['exact'][$name] = $this
          ->prepareAttributeValues($values);
      }
    }
    krsort($allowed_attributes['prefix']);

    // 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);
    }
  }
  if ($this->settings['filter_html_nofollow']) {
    $links = $html_dom
      ->getElementsByTagName('a');
    foreach ($links as $link) {
      $link
        ->setAttribute('rel', 'nofollow');
    }
  }
  $text = Html::serialize($html_dom);
  return trim($text);
}