在PHP中将CSS白名单应用于HTML [关闭]

Lets say I have the following $string...

<span style='text-decoration:underline; display:none;'>Some text</span>

I only want to allow the style text-decoration, so I want a PHP function like the following...

$string = stripStyles($string, array("text-decoration"));

Similar to strip_tags, but using an array instead. So $string will now be...

<span style='text-decoration:underline;'>Some text</span>

I am using Cake, so if this can be done with Sanitize then all the better.

This is tricky, but you should be able to do it with DOMDocument. This should get you started, but it's likely to require some serious tweaking.

// Load your html string
$dom = new DOMDocument();
$dom->loadHTML($your_html_string);

// Get all the <span> tags
$spans = $dom->getElementsByTagName("span");

// Loop over the span tags
foreach($spans as $span) {

  // If they have a style attribute that contains "text-decoration:"
  // attempt to replace the contents of the style attribute with only the text-decoration component.
  if ($style = $span->getAttribute("style")) {
    if (preg_match('/text-decoration:([^;]*);/i', $style)) {
      $span->setAttribute("style", preg_replace('/^(.*)text-decoration:([^;]*);(.*)$/i', "text-decoration:$2;", $style);
    }
    // Otherwise, erase the style attribute
    else $span->setAttribute("style", "");
  }
}

$output = $dom->saveHTML;

It's maybe better to attempt to parse the style attributes by explode()ing on ;

// This replaces the inner contents of the foreach ($spans as $span) above...

// Instead of the preg_replace()
$styles = explode(";", $style);
$replaced_style = FALSE;
foreach ($styles as $s) {
 if (preg_match('/text-decoration/', $s) {
   $span->setAttribute("style", $s);
   $replaced_style = TRUE;
 }
 //  If a text-decoration wasn't found, empty out the style
 if (!$replaced_style) $span->setAttribute("style", "");
}