tanaka's Programming Memo

プログラミングについてのメモ。

PHP DOMDocumentのloadHTML() ShiftJISでエラー

①などの文字が含まれるHTMLページをDOMDocumentのloadHTML()でDOMにしようとしたところ、以下のようなエラーが発生してしまいました。

DOMDocument::loadHTML(): input conversion failed due to input error, bytes 0x81 0xAE 0xE3 0x81

やりたいことは、ShiftJISのページをUTF-8にして、SimpleXMLElementに変換することです。

[PHP] DOMDocument#loadHTML()で、特定の文字が含まれていると正しいDOMを作ってくれない を拝読することで解決しました。

原因1

根本的な原因は、機種依存文字を利用したことです。しかし、①などはUTF-8にも定義されているのでエンコードの指定が合っていれば変換できます。

①などのWindows機種依存文字まで含めたエンコードは、 CP932 や sjis_win などと呼び、ShiftJISとは別に指定することができます。

解決策

$urlに読み込みたいWebページのURLが入っているとして、以下のようにして変換します。

<?php
// URLからHTMLの取得
$html = file_get_contents($url);

// windows用のSJISからUTF8に変換
$html = mb_convert_encoding($html, "UTF-8", "SJIS-win");
// HTMLのcharsetを変換に合わせて修正する
$html = str_replace("charset=shift_jis", "charset=utf-8", $html);

// HTMLをDOMに変換
$domDocument = new domDocument();
$domDocument->loadHTML($html);

// XMLに変換
$xmlstr = $domDocument->saveXML();

// SimpleXMLElementに読み込み
$xml = simplexml_load_string($xmlstr);

原因2

&記号が本文中などにあるとエラーになります。 & でエスケープが必要です。

おまけ

loadHTML()は、読み込ませるHTMLファイルのcharsetに合わせて文字コードを自動的にUTF-8に変換してくれます。そのため、特殊な文字が使われていないShiftJISのページなら、何も考えずにloadHTML()に突っ込んで大丈夫です。