1 filter.module filter_format_allowed_html($format)

Get a complete list of allowed and forbidden tags for a text format.

Parameters

$format: The text format object for which the list will be generated.

Return value

array|TRUE: An array of allowed HTML with the following keys:

  • allowed: A list of allowed tags keyed by tag name. The value is an array of attributes.
  • forbidden: An unindexed array of tags that are not allowed.

For the full documentation on the return values of these two properties, see callback_filter_allowed_html(). If TRUE is returned, then there are no restrictions on this format's HTML content.

See also

callback_filter_allowed_html()

File

core/modules/filter/filter.module, line 493
Framework for handling the filtering of content.

Code

function filter_format_allowed_html($format) {
  $all_filter_info = filter_get_filters();
  $all_html_allowed = TRUE;
  $restrictions = array(
    'allowed' => array(),
    'forbidden' => array(),
  );

  foreach ($format->filters as $filter_name => $filter) {
    // Skip disabled filters.
    if (!$filter->status) {
      continue;
    }
    // Skip non-existent filters.
    if (!isset($all_filter_info[$filter_name])) {
      continue;
    }
    // We're only concerned with filters that specify an allowed HTML callback.
    $filter_info = $all_filter_info[$filter_name];
    if (!isset($filter_info['allowed html callback'])) {
      continue;
    }

    $allowed_html_callback = $filter_info['allowed html callback'];
    $filter_restrictions = $allowed_html_callback($filter, $format);

    if ($filter_restrictions) {
      $all_html_allowed = FALSE;
    }
    else {
      continue;
    }

    // Forbidden tags are simple in that they have no attributes to track, it's
    // just a list of tags that are not allowed.
    if (isset($filter_restrictions['forbidden'])) {
      $restrictions['forbidden'] = array_unique(array_merge($restrictions['forbidden'], $filter_restrictions['forbidden']));
    }

    // Add any allowed tags that have not yet been specified and build a list
    // of any that need to be intersected.
    $intersected_tags = array();
    foreach ($filter_restrictions['allowed'] as $tag => $attributes) {
      if (!isset($restrictions['allowed'][$tag])) {
        $restrictions['allowed'][$tag] = $attributes;
      }
      else {
        $intersected_tags[$tag] = $attributes;
      }
    }

    // Allowed tags are more complicated as different filters may allow
    // different individual attributes. Track the intersection of all allowed
    // attributes for each tag.
    foreach ($intersected_tags as $tag => $attributes) {
      $intersection = NULL;
      $current_attributes = isset($restrictions['allowed'][$tag]) ? $restrictions['allowed'][$tag] : array();
      $new_attributes = $filter_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 fewer attributes (all -> list or none).
      elseif (!is_array($current_attributes) && $current_attributes == TRUE && ($new_attributes == FALSE || is_array($new_attributes))) {
        $intersection = $new_attributes;
      }
      // The new filter allows fewer attributes (list -> none).
      elseif (is_array($current_attributes) && $new_attributes == FALSE) {
        $intersection = $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 = array_intersect_key($current_attributes, $new_attributes);
        foreach (array_keys($intersection) as $attribute_value) {
          $intersection[$attribute_value] = $intersection[$attribute_value] && $new_attributes[$attribute_value];
        }
      }
      if (isset($intersection)) {
        $restrictions['allowed'][$tag] = $intersection;
      }
    }
  }

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

  // Simplification: if the only remaining allowed tag is the asterisk (which
  // contains attribute restrictions that apply to all tags), and only allow
  // 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'])) {
      $restrictions['allowed'] = array();
    }
  }

  // If no filters specified restrictions, change the allowed values to be
  // a Boolean.
  if ($all_html_allowed) {
    $restrictions = TRUE;
  }

  return $restrictions;
}