5

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> 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.

4
  • I don't understand. You want to get "the content" with special characters converted, but special characters not converted? Commented Jun 13, 2011 at 14:26
  • I don't want to get the content - I have the content - I want to convert it - so that & becomes &amp; etc., but this function wouldn't convert html tags - so <div class="some_class"> would remain untouched Commented Jun 13, 2011 at 14:32
  • What version of php are you using? If it is >= 5.3.6 you can add a parameter to savehtml to specify which node you want to save. Commented Jun 13, 2011 at 14:37
  • I'm working on 5.2, but system eventually will work on the latest version of PHP - would you mind including the example? Commented Jun 13, 2011 at 14:41

4 Answers 4

5

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);
Sign up to request clarification or add additional context in comments.

5 Comments

note that any html tag with attributes won't be translated properly unless you also unset the double quote (")
Yes - well, it's not ideal really as I want double quotes to also be converted to &quot; if found within the content and not associated with html tag
@user398341: Why? It doesn’t need to be encoded except for in double quote attribute values.
This one returned the following error when validating html: Sorry, I am unable to validate this document because on line 179 it contained one or more bytes that I cannot interpret as utf-8 (in other words, the bytes found are not valid values in the specified Character Encoding). Please check both the content of the file and the character encoding indication. The error was: utf8 "\x80" does not map to Unicode
@user398341: You might need to adjust get_html_translation_table’s charset_hint parameter.
4

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;
?>

1 Comment

Well, people may advice against it, but I am very gratefull for your post. For people who wonder why one would wish to use such a thing? My company have medical extracts and we give people the option to share them on their site. But when utf encoding characters such as ë they get translated to a weird mixup. But our own text has html markup. So, to get around the problem I need to filter out the "bad" characters, but to keep the good ones(our own html code). Jus a real world example for those who can never see a use for this.
0

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.

1 Comment

Thanks for that - however, the output is only modified by admin - so no external input. For visitors I would use completely different approach. The content which this method outputs is coming from CKEditor so majority of it already converted to relevant symbols, however there might be an instance that I will have to use this function to convert some other input as well. With less then sign '<' or more than '>' - I don't really see any problems - if I was about to allow visitors to add some content - I would most probably use strip_tags() function and allow only certain or none of html tags.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.