开发者

PHP htmlentities() without converting html tags

I've found a few posts which refer to the problem, but none of them fully resolve it.

I need the function which will output the content converting all special characters in the way the htmlentities() would, but preserving all html tags.

I've tried many different approaches, but as I've mentioned above - none of them works as expected.

I was wondering whether there would be a way of doing it using PHP class DomDocument.

I've tried to do it using the following:

$objDom = new DOMDocument('1.0', 'utf-8');
$objDom->loadhtml($content);
return $objDom->savehtml();

which works, but it also adds the entire structure of the page i.e.

<head><body> 开发者_JS百科etc.

I only need the content of the $content variable to be converted and job done.

Another thing worth to mention here is that $content might also have some characters converted to xhtml complaint - as it comes from Wysiwyg. So it might containt & etc., which should also be preserved.

Anyone knows the way to do it with DomDocument - perhaps I should use different save method?

Ok - I've come up with the following - not great, but does the job spot on:

$objDom = new DOMDocument('1.0', 'UTF-8');
$objDom->loadHTML($string);
$output = $objDom->saveXML($objDom->documentElement);
$output = str_replace('<html><body>', '', $output);
$output = str_replace('</body></html>', '', $output);
$output = str_replace('&#13;', '', $output);
return $output; 

Any better ideas would be much appreciated.


You could use get_html_translation_table and remove the < and > items:

$trans = get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
unset($trans['<'], $trans['>']);
$output = strtr($input, $trans);


get_html_translation_table(HTML_ENTITIES) gives you the translation table used in htmlentities() as an array. You can remove <, > and " from the array like so:

<?php
$trans = get_html_translation_table(HTML_ENTITIES);
unset($trans["\""], $trans["<"], $trans[">"]);
$str = "Hallo <strong>& Frau</strong> & Krämer";
$encoded = strtr($str, $trans);

echo $encoded;
?>


Let me begin by saying that, in my opinion, what you are trying to do is fundementally wrong. What if someone wants to type a less-than sign? Personally, I see htmlentities() as a way to make sure users can't enter their own HTML code.

If you need users to be able to style text, there are many solutions already made for that (check out TinyMCE or Markdown, for example).

If you must allow users to input HTML tags, and you must assume they don't know how to use entities, here is a simple function that works:

function my_htmlentities ($str)
{
  // We'll append everything to this.
  $result = '';

  // Continue while there are HTML tags.
  while (($lt = strpos($str, '<')) !== false)
  {
    // Run `htmlentities` on everything before the tag, and pop it 
    // off the original string.
    $result .= htmlentities(substr($str, 0, $lt));
    $str = substr($str, $lt);

    // We want to continue until we reach the end of the tag. I know 
    // these loops are bad form. Sorry. I still think in F77 :p
    while (true)
    {
      // Find the closing tag as well as quotes.
      $gt = strpos($str, '>');
      $quot = strpos($str, '"');

      // If there is no closing bracket, append the rest of the tag 
      // as plaintext and exit.
      if ($gt === false)
        return $result . $str;

      // If there is a quote before the closing bracket, take care 
      // of it.
      if ($quot !== false && $quot < $gt)
      {
        // Grab everything before the quote.
        $result .= substr($str, 0, $quot+1);
        $str = substr($str, $quot+1);

        // Find the closing quote (if there is none, append and 
        // exit).
        if (($quot = strpos($str, '"')) === false)
          return $result . $str;

        // Grab the inside of the quote.
        $result .= substr($str, 0, $quot+1);
        $str = substr($str, $quot+1);

        // Start over as if we were at the beginning of the tag.
        continue;
      }

      // We just have the closing bracket to deal with. Deal.
      $result .= substr($str, 0, $gt+1);
      $str = substr($str, $gt+1);
      break;
    }
  }

  // There are no more tags, so we can run `htmlentities()` on the 
  // rest of the string.
  return $result . htmlentities($str);

  // Alternatively, if you want users to be able to enter their own
  // entities as well, you'll have to use this last line instead:
  return str_replace('&amp;', '&', $result . htmlentities($str));
}

But please let me reiterate: this is extremely insecure! I'll give you the benefit of the doubt that you know what you want, but I don't think you (or anyone) should want this.


Ok - after a lot of research I've come up with the final option - which seem to be just what I needed.

I've used the HTMLPurifier and filtered my content using the following:

require_once('HTMLPurifier/HTMLPurifier.auto.php');
$config = HTMLPurifier_Config::createDefault();
$config->set('HTML.Doctype', 'XHTML 1.0 Transitional');
$objPurifier = new HTMLPurifier($config);
return $objPurifier->purify($string);

I hope someone else will find it useful.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜