title: PHP DOM UTF-8 problem
body: <p>First of all, my database uses Windows-1250 as native charset. I am outputting the data as UTF-8. I'm using iconv() function all over my website to convert Windows-1250 strings to UTF-8 strings and it works perfect.</p>
  
  <p>The problem is when I'm using PHP DOM to parse some HTML stored in the database (the HTML is an output from a  WYSIWYG editor and is not valid, it has no html, head, body tags etc).</p>
  
  <p>The HTML could look something like this, for example:</p>
  
  <pre><code>&lt;p&gt;Hello&lt;/p&gt;
  </code></pre>
  
  <p>Here is a method I use to parse a certain HTML from the database:</p>
  
  <pre><code> private function ParseSlideContent($slideContent)
   {
          var_dump(iconv('Windows-1250', 'UTF-8', $slideContent)); // this outputs the HTML ok with all special characters
  
    $doc = new DOMDocument('1.0', 'UTF-8');
  
    // hack to preserve UTF-8 characters
    $html = iconv('Windows-1250', 'UTF-8', $slideContent);
    $doc-&gt;loadHTML('&lt;?xml encoding="UTF-8"&gt;' . $html);
    $doc-&gt;preserveWhiteSpace = false;
  
    foreach($doc-&gt;getElementsByTagName('img') as $t) {
     $path = trim($t-&gt;getAttribute('src'));
     $t-&gt;setAttribute('src', '/clientarea/utils/locate-image?path=' . urlencode($path));
    }
    foreach ($doc-&gt;getElementsByTagName('object') as $o) {
     foreach ($o-&gt;getElementsByTagName('param') as $p) {
      $path = trim($p-&gt;getAttribute('value'));
      $p-&gt;setAttribute('value', '/clientarea/utils/locate-flash?path=' . urlencode($path));
     }
    }
    foreach ($doc-&gt;getElementsByTagName('embed') as $e) {
     if (true === $e-&gt;hasAttribute('pluginspage')) {
      $path = trim($e-&gt;getAttribute('src'));
      $e-&gt;setAttribute('src', '/clientarea/utils/locate-flash?path=' . urlencode($path));
     } else {
      $path = end(explode('data/media/video/', trim($e-&gt;getAttribute('src'))));
      $path = 'data/media/video/' . $path;
      $path = '/clientarea/utils/locate-video?path=' . urlencode($path);
      $width = $e-&gt;getAttribute('width') . 'px';
      $height = $e-&gt;getAttribute('height') . 'px';
      $a = $doc-&gt;createElement('a', '');
      $a-&gt;setAttribute('href', $path);
      $a-&gt;setAttribute('style', "display:block;width:$width;height:$height;");
      $a-&gt;setAttribute('class', 'player');
      $e-&gt;parentNode-&gt;replaceChild($a, $e);
      $this-&gt;slideContainsVideo = true;
     }
    }
  
    $html = trim($doc-&gt;saveHTML());
  
    $html = explode('&lt;body&gt;', $html);
    $html = explode('&lt;/body&gt;', $html[1]);
    return $html[0];
   }
  </code></pre>
  
  <p>The output from the method above is a garbage with all special characters replaced with weird stuff like ÃšÄ�.</p>
  
  <p>One more thing. It <strong>does work</strong> on my development server.</p>
  
  <p>It does not work on the production server though.</p>
  
  <p>Any suggestions?</p>
  
  <p>PHP version of the production server: PHP Version 5.2.0RC4-dev</p>
  
  <p>PHP version of the development server: PHP Version 5.2.13</p>
  
  <hr>
  
  <p>UPDATE:</p>
  
  <p>I'm working on a solution myself. I have an inspiration from this PHP bug report (not really a bug though): <a href="http://bugs.php.net/bug.php?id=32547" rel="nofollow noreferrer">http://bugs.php.net/bug.php?id=32547</a></p>
  
  <p>This is my proposed solution. I will try it tomorrow and let you know if it works:</p>
  
  <pre><code> private function ParseSlideContent($slideContent)
   {
          var_dump(iconv('Windows-1250', 'UTF-8', $slideContent)); // this outputs the HTML ok with all special characters
  
    $doc = new DOMDocument('1.0', 'UTF-8');
  
    // hack to preserve UTF-8 characters
    $html = iconv('Windows-1250', 'UTF-8', $slideContent);
    $doc-&gt;loadHTML('&lt;?xml encoding="UTF-8"&gt;' . $html);
    $doc-&gt;preserveWhiteSpace = false;
  
    // this might work
    // it basically just adds head and meta tags to the document
    $html = $doc-&gt;getElementsByTagName('html')-&gt;item(0);
    $head = $doc-&gt;createElement('head', '');
    $meta = $doc-&gt;createElement('meta', '');
    $meta-&gt;setAttribute('http-equiv', 'Content-Type');
    $meta-&gt;setAttribute('content', 'text/html; charset=utf-8');
    $head-&gt;appendChild($meta);
    $body = $doc-&gt;getElementsByTagName('body')-&gt;item(0);
    $html-&gt;removeChild($body);
    $html-&gt;appendChild($head);
    $html-&gt;appendChild($body);
  
    foreach($doc-&gt;getElementsByTagName('img') as $t) {
     $path = trim($t-&gt;getAttribute('src'));
     $t-&gt;setAttribute('src', '/clientarea/utils/locate-image?path=' . urlencode($path));
    }
    foreach ($doc-&gt;getElementsByTagName('object') as $o) {
     foreach ($o-&gt;getElementsByTagName('param') as $p) {
      $path = trim($p-&gt;getAttribute('value'));
      $p-&gt;setAttribute('value', '/clientarea/utils/locate-flash?path=' . urlencode($path));
     }
    }
    foreach ($doc-&gt;getElementsByTagName('embed') as $e) {
     if (true === $e-&gt;hasAttribute('pluginspage')) {
      $path = trim($e-&gt;getAttribute('src'));
      $e-&gt;setAttribute('src', '/clientarea/utils/locate-flash?path=' . urlencode($path));
     } else {
      $path = end(explode('data/media/video/', trim($e-&gt;getAttribute('src'))));
      $path = 'data/media/video/' . $path;
      $path = '/clientarea/utils/locate-video?path=' . urlencode($path);
      $width = $e-&gt;getAttribute('width') . 'px';
      $height = $e-&gt;getAttribute('height') . 'px';
      $a = $doc-&gt;createElement('a', '');
      $a-&gt;setAttribute('href', $path);
      $a-&gt;setAttribute('style', "display:block;width:$width;height:$height;");
      $a-&gt;setAttribute('class', 'player');
      $e-&gt;parentNode-&gt;replaceChild($a, $e);
      $this-&gt;slideContainsVideo = true;
     }
    }
  
    $html = trim($doc-&gt;saveHTML());
  
    $html = explode('&lt;body&gt;', $html);
    $html = explode('&lt;/body&gt;', $html[1]);
    return $html[0];
   }
  </code></pre>