DOMDocument->loadHTML()でパースすると文字化けする
大体HTMLに原因があるのでそこを見ればよい。
- 原因1: CP932なのにmeta charset=Shift_JISになっている
- 原因2: meta charsetは正しいが、それより前にマルチバイト文字がある
- 原因3: そもそもmeta charsetがない
ブラウザが「いい感じ」に処理してくれるのもダメHTMLがいまだに駆逐されない原因の一つじゃないだろうか。
正しく処理するには、HTMLの頭に正しいmeta charset指定を補うのが一番速いだろうと思う。
ただ(3)のmeta charsetがない場合、mb_detect_encoding()
で見当をつけるにも言語を絞り込まないと限界があるので、結構難しい。
ちなみにコンストラクタで文字コードを指定できるが、HTML処理では全く使われない。
$doc = new DOMDocument(null, 'UTF-8');
$doc->loadHTMLFile()
の場合PHPはlibxmlの htmlCreateFileParserCtxt()
にエンコーディングを渡しておらず、$doc->loadHTML()
の場合 htmlCreateMemoryParserCtxt()
にはエンコーディングを指定できないようになっている。
$doc->saveHTML() で出力する
パースしたHTMLを変形して出力することもあると思うが、libxml2 2.9.8 時点では <meta charset="...">
で指定していると保存するべきエンコーディングを発見できず、出力がHTMLエンティティだらけになる。
そのため<meta http-equiv="Content-Type" content="text/html; charset=...">
で指定する必要がある。
そもそもHTML4のパースと言っているので、HTML5の記法には対応していないということだろうか。読み込みでは認識しているようにも見えるが深く追っていない。