FilterFormat::getHtmlRestrictions

public FilterFormat::getHtmlRestrictions()

Retrieve all HTML restrictions (tags and attributes) for the text format.

Note that restrictions applied to the "*" tag (the wildcard tag, i.e. all tags) are treated just like any other HTML tag. That means that any restrictions applied to it are not automatically applied to all other tags. It is up to the caller to handle this in whatever way it sees fit; this way no information granularity is lost.

Return value

array|false A structured array as returned by FilterInterface::getHTMLRestrictions(), but with the intersection of all filters in this text format. Will either indicate blacklisting of tags or whitelisting of tags. In the latter case, it's possible that restrictions on attributes are also stored. FALSE means there are no HTML restrictions.

Overrides FilterFormatInterface::getHtmlRestrictions

File

core/modules/filter/src/Entity/FilterFormat.php, line 270

Class

FilterFormat
Represents a text format.

Namespace

Drupal\filter\Entity

Code

public function getHtmlRestrictions() {
  // Ignore filters that are disabled or don't have HTML restrictions.
  $filters = array_filter($this->filters()->getAll(), function($filter) {
    if (!$filter->status) {
      return FALSE;
    }
    if ($filter->getType() === FilterInterface::TYPE_HTML_RESTRICTOR && $filter->getHTMLRestrictions() !== FALSE) {
      return TRUE;
    }
    return FALSE;
  });

  if (empty($filters)) {
    return FALSE;
  }
  else {
    // From the set of remaining filters (they were filtered by array_filter()
    // above), collect the list of tags and attributes that are allowed by all
    // filters, i.e. the intersection of all allowed tags and attributes.
    $restrictions = array_reduce($filters, function($restrictions, $filter) {
      $new_restrictions = $filter->getHTMLRestrictions();

      // The first filter with HTML restrictions provides the initial set.
      if (!isset($restrictions)) {
        return $new_restrictions;
      }
      // Subsequent filters with an "allowed html" setting must be intersected
      // with the existing set, to ensure we only end up with the tags that are
      // allowed by *all* filters with an "allowed html" setting.
      else {
        // Track the union of forbidden (blacklisted) tags.
        if (isset($new_restrictions['forbidden_tags'])) {
          if (!isset($restrictions['forbidden_tags'])) {
            $restrictions['forbidden_tags'] = $new_restrictions['forbidden_tags'];
          }
          else {
            $restrictions['forbidden_tags'] = array_unique(array_merge($restrictions['forbidden_tags'], $new_restrictions['forbidden_tags']));
          }
        }

        // Track the intersection of allowed (whitelisted) tags.
        if (isset($restrictions['allowed'])) {
          $intersection = $restrictions['allowed'];
          foreach ($intersection as $tag => $attributes) {
            // If the current tag is not whitelisted by the new filter, then
            // it's outside of the intersection.
            if (!array_key_exists($tag, $new_restrictions['allowed'])) {
              // The exception is the asterisk (which applies to all tags): it
              // does not need to be whitelisted by every filter in order to be
              // used; not every filter needs attribute restrictions on all tags.
              if ($tag === '*') {
                continue;
              }
              unset($intersection[$tag]);
            }
            // The tag is in the intersection, but now we must calculate the
            // intersection of the allowed attributes.
            else {
              $current_attributes = $intersection[$tag];
              $new_attributes = $new_restrictions['allowed'][$tag];
              // The current intersection does not allow any attributes, never
              // allow.
              if (!is_array($current_attributes) && $current_attributes == FALSE) {
                continue;
              }
              // The new filter allows less attributes (all -> list or none).
              elseif (!is_array($current_attributes) && $current_attributes == TRUE && ($new_attributes == FALSE || is_array($new_attributes))) {
                $intersection[$tag] = $new_attributes;
              }
              // The new filter allows less attributes (list -> none).
              elseif (is_array($current_attributes) && $new_attributes == FALSE) {
                $intersection[$tag] = $new_attributes;
              }
              // The new filter allows more attributes; retain current.
              elseif (is_array($current_attributes) && $new_attributes == TRUE) {
                continue;
              }
              // The new filter allows the same attributes; retain current.
              elseif ($current_attributes == $new_attributes) {
                continue;
              }
              // Both list an array of attribute values; do an intersection,
              // where we take into account that a value of:
              //  - TRUE means the attribute value is allowed;
              //  - FALSE means the attribute value is forbidden;
              // hence we keep the ANDed result.
              else {
                $intersection[$tag] = array_intersect_key($intersection[$tag], $new_attributes);
                foreach (array_keys($intersection[$tag]) as $attribute_value) {
                  $intersection[$tag][$attribute_value] = $intersection[$tag][$attribute_value] && $new_attributes[$attribute_value];
                }
              }
            }
          }
          $restrictions['allowed'] = $intersection;
        }

        return $restrictions;
      }
    }, NULL);

    // Simplification: if we have both a (intersected) whitelist and a (unioned)
    // blacklist, then remove any tags from the whitelist that also exist in the
    // blacklist. Now the whitelist alone expresses all tag-level restrictions,
    // and we can delete the blacklist.
    if (isset($restrictions['allowed']) && isset($restrictions['forbidden_tags'])) {
      foreach ($restrictions['forbidden_tags'] as $tag) {
        if (isset($restrictions['allowed'][$tag])) {
          unset($restrictions['allowed'][$tag]);
        }
      }
      unset($restrictions['forbidden_tags']);
    }

    // Simplification: if the only remaining allowed tag is the asterisk (which
    // contains attribute restrictions that apply to all tags), and only
    // whitelisting filters were used, then effectively nothing is allowed.
    if (isset($restrictions['allowed'])) {
      if (count($restrictions['allowed']) === 1 && array_key_exists('*', $restrictions['allowed']) && !isset($restrictions['forbidden_tags'])) {
        $restrictions['allowed'] = array();
      }
    }

    return $restrictions;
  }
}
doc_Drupal
2016-10-29 09:14:32
Comments
Leave a Comment

Please login to continue.