ポンコツエンジニアのごじゃっぺ開発日記。

いろいろポンコツだけど、気にするな。エンジニアの日々の開発などの記録を残していきます。 自動で収入を得られるサービスやシステムを作ることが目標!!

【PHP】loadHTMLでエラーが発生、その原因と解決策。

PHPのDOMDocumentを利用すると、HTMLやXMLのドキュメントに対して検索したり、アクセスしたりできるかと思います。

www.php.net

この中の文字列からHTMLを読み込むときに使用するloadHTMLを使っていて、問題が発生した時の原因と解決策のメモを書いた記事になります。

www.php.net

エラー発生

まずは、ドキュメントにも書いてあるサンプルプログラムから以下のようにシンプルな処理を作成しました

<?php
$doc = new DOMDocument();
$doc->loadHTML("<html><body>Test<br></body></html>");
echo $doc->saveHTML();

これを実行すると以下のように生成されたHTMLが出力されます。

$ php test.php
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>Test<br></body></html>

これに対して、以下のように&を入れた文字列に変更してみました。

<?php
$doc = new DOMDocument();
$doc->loadHTML("<html><body>Test&<br></body></html>");
echo $doc->saveHTML();

Test&のところです。 これを実行すると、、、

$ php test.php

Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entity, line: 1 in /Users/pnkts/test.php on line 3
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>Test&amp;<br></body></html>

このように、Warning: DOMDocument::loadHTML(): htmlParseEntityRef: no name in Entityというワーニングが出力されました。

これは大変。それ以外にも、もしかしたらリンクのURLにクエリパラメータをつけることもあるかもしれないです。

ということで確認です!

<?php
$doc = new DOMDocument();
$doc->loadHTML('<html><body><a href="./test?a=1&b=1">Test</a><br></body></html>');

これを実行すると、、、

$ php test.php

Warning: DOMDocument::loadHTML(): htmlParseEntityRef: expecting ';' in Entity, line: 1 in /Users/pnkts/test.php on line 3
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><a href="./test?a=1&amp;b=1">Test</a><br></body></html>

このように、Warning: DOMDocument::loadHTML(): htmlParseEntityRef: expecting ';' in Entityというワーニングメッセージが出力されてしまいました。

解決策

こちらの記事を参考にしました。

stackoverflow.com

libxml_use_internal_errorsを用いて、libxmlエラーを無効にして、後からエラー情報を取得する形に変更します。この記事ではエラー情報の取得は行いませんので、取得したい場合はドキュメントを参考にしてみてください。

www.php.net

戻り値がuse_errorsの前の値が変えるので、処理が終わったらその値を利用して元に戻してあげます。

<?php
$doc = new DOMDocument();

// set error level
$internalErrors = libxml_use_internal_errors(true);

$doc->loadHTML('<html><body><a href="./test?a=1&b=1">Test</a><br></body></html>');

// Restore error level
libxml_use_internal_errors($internalErrors);

echo $doc->saveHTML();

これを実行すると、、、

$ php test.php
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><a href="./test?a=1&amp;b=1">Test</a><br></body></html>

ワーニングなく実行できたことがわかります。ただし、&(アンパサンド)のところが&amp;に置換されてしまっているので注意しなきゃですね。

もちろん、@でエラーを握りつぶしてしまっても良いかと思います。

<?php
$doc = new DOMDocument();

@$doc->loadHTML('<html><body><a href="./test?a=1&b=1">Test</a><br></body></html>');

echo $doc->saveHTML();
php test.php
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><a href="./test?a=1&amp;b=1">Test</a><br></body></html>

無事、ワーニングなく正常に実行することができました。

「&amp;」を「&」に変換する

では、&amp;を普通の表示にさせたいですよね。と思って考えたのは、htmlspecialchars_decodeの使用です。

www.php.net

<?php
$doc = new DOMDocument();

@$doc->loadHTML('<html><body><a href="./test?a=1&b=1">Test</a><br></body></html>');

echo htmlspecialchars_decode($doc->saveHTML());

最後の出力のときに、htmlspecialchars_decodeを挟んでみました。

$ php test.php
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><a href="./test?a=1&b=1">Test</a><br></body></html>

実行してみると、このようにこの例では問題なく良い感じに出力されるようになりました。

ということで、一旦解決としました!

お問い合わせプライバシーポリシー制作物