【PHP8.x】recoverプロパティの使い方
recoverプロパティの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
recoverプロパティは、PHPのDOMDocumentクラスがHTML文書を解析する際の、エラー回復モードの状態を保持するプロパティです。このプロパティは、DOMDocumentクラスを用いてHTML文書を読み込む際に、構文エラーや不完全な記述がある場合でも、システムが可能な限り文書の解析を続行し、DOMツリーを構築しようとするかどうかを制御します。
具体的には、recoverプロパティをtrueに設定すると、HTMLの記述に軽微な誤りがあっても、DOMDocumentはそれを修正しようと試みながら解析を続けます。これにより、記述ミスのあるHTMLであっても、ある程度の内容を読み取り、DOMオブジェクトとして扱えるようになる可能性が高まります。一方、既定値であるfalseの場合、HTMLが厳密な整形式でないと判断されると、解析が途中で停止したり、不完全なDOMツリーしか構築されないことがあります。
このプロパティは、主に外部ソースから取得したHTMLや、手書きで記述されたもので、必ずしも完璧な整形式ではない可能性のある文書を扱う場合に役立ちます。HTML文書をloadHTML()やloadHTMLFile()メソッドで読み込む前に設定する必要があり、より堅牢なHTML解析処理を実装するのに貢献します。ただし、この機能は文書の構造を完璧に修復するものではなく、元のHTMLの品質によっては期待通りの結果が得られない場合もありますのでご注意ください。
構文(syntax)
1<?php 2 3$dom = new DOMDocument(); 4$dom->recover = true;
引数(parameters)
引数なし
引数はありません
戻り値(return)
bool
このプロパティは、DOMDocumentが解析中にエラーを検出した場合に、可能な限りドキュメントの復旧を試みるかどうかを示すブール値を返します。trueの場合は復旧を試み、falseの場合は試みません。
サンプルコード
PHP DOMDocument::recoverでHTMLを修復する
1<?php 2 3/** 4 * DOMDocument::recover プロパティの使用例 5 * 非整形式のHTMLをパースする際に、リカバリーモードを有効にする方法を示します。 6 * 7 * @param string $htmlString パースするHTML文字列 8 * @return string|false パースされたHTML、またはエラー時はfalse 9 */ 10function parseHtmlWithRecovery(string $htmlString): string|false 11{ 12 // 新しいDOMDocumentインスタンスを作成します。 13 $dom = new DOMDocument(); 14 15 // DOMDocument::recover プロパティをtrueに設定します。 16 // これにより、DOMDocument::loadHTML() が非整形式のHTML(例: 閉じられていないタグ)を処理する際に、 17 // エラー報告を抑制し、可能な限り文書構造を修正してパースを試みます。 18 // HTMLパーサーが一般的なエラーを「回復」し、有効なDOMツリーを構築しようとします。 19 $dom->recover = true; 20 21 // HTML文字列をDOMに読み込みます。 22 // LIBXML_HTML_NOIMPLIED: HTML5文書としてパースする際、余分な <html> や <body> タグを自動追加しないようにします。 23 // LIBXML_HTML_NODEFDTD: デフォルトのDTD(Document Type Definition)を自動追加しないようにします。 24 // これらのオプションは、通常、よりクリーンなHTMLパース結果を得るために使われます。 25 if ($dom->loadHTML($htmlString, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD)) { 26 // パース結果のHTMLを文字列として返します。 27 return $dom->saveHTML(); 28 } else { 29 // HTMLのパースに失敗した場合(非常に稀ですが、発生する可能性はあります)。 30 return false; 31 } 32} 33 34// 非整形式のHTMLの例 35// 以下のHTMLには、閉じられていない <span> タグや <b> タグが含まれています。 36// ブラウザはこのようなエラーを自動修正しますが、DOMDocumentはrecoverがtrueでないとエラーを報告します。 37$malformedHtml = <<<HTML 38<!DOCTYPE html> 39<html> 40<head> 41 <title>Malformed HTML Example</title> 42</head> 43<body> 44 <h1>DOMDocument::recover プロパティのデモンストレーション</h1> 45 <p>この段落には、閉じられていない <span>span タグ が含まれています。</p> 46 <p>もう一つの段落には、閉じられていない <b>bold タグ があります。</p> 47 <div> 48 <p>3番目の段落です。</p> 49 </div> 50</body> 51</html> 52HTML; 53 54// 元の非整形式のHTMLを表示します。 55echo "<h3>--- 元の非整形式HTML ---</h3>"; 56echo '<pre>' . htmlspecialchars($malformedHtml) . '</pre>'; 57 58// recoverプロパティを有効にしてHTMLをパースします。 59$recoveredHtml = parseHtmlWithRecovery($malformedHtml); 60 61if ($recoveredHtml !== false) { 62 // パースされ、修正されたHTMLを表示します。 63 echo "<h3>--- recover=true でパースされたHTML ---</h3>"; 64 echo '<pre>' . htmlspecialchars($recoveredHtml) . '</pre>'; 65 echo "<p><em>上記のHTMLは、<code>DOMDocument::recover = true;</code> の設定により、<br>非整形式のHTMLがエラーなしでパースされ、可能な限り文書構造が修正された結果です。<br>例えば、閉じられていなかった <code><span></code> や <code><b></code> タグが自動的に閉じられています。</em></p>"; 66} else { 67 echo "<p><em>HTMLのパースに失敗しました。</em></p>"; 68} 69 70?>
PHPのDOMDocumentクラスが提供するrecoverプロパティは、非整形式(構文的に正しくない)なHTML文書をパースする際に、エラーを抑制し、可能な限り文書構造を修正して処理するための機能です。このプロパティは引数を取らず、trueまたはfalseのブール値を設定することで、リカバリーモードの有効・無効を切り替えます。
サンプルコードでは、parseHtmlWithRecovery関数内で新しいDOMDocumentインスタンスを作成し、そのrecoverプロパティをtrueに設定しています。これにより、続くloadHTMLメソッドが、例えば閉じられていない<span>タグや<b>タグといったエラーを含むHTML文字列を読み込む際、通常の厳格なチェックを緩和し、ブラウザがエラーを自動修正するように、可能な限り有効なDOMツリーを構築しようとします。
パースが成功すると、saveHTMLメソッドによって修正されたHTML文字列が返されます。この関数は、パースの成否を示すブール値を返すのではなく、パースされたHTML文字列か、処理失敗時にはfalseを返します。これにより、開発者は不正なHTMLであっても、その内容をできるだけ活用して処理を継続することが可能になります。サンプルコードは、このリカバリーモードが非整形式のHTMLをどのように「修復」して表示するかを具体的に示しています。
DOMDocument::recoverプロパティは、閉じタグの不足など、少し壊れたHTMLでもエラーを出さずにパースし、可能な限り自動で修正する便利な機能です。しかし、元のHTMLとは異なる構造に修正される場合があるため、パース結果が意図した通りか確認が必要です。完全に破損したHTMLはパースできないこともありますので、loadHTMLの成功を必ずチェックしてください。外部からの信頼できないHTMLを処理する際は、予期せぬDOM構造の変更やセキュリティ上のリスクを避けるため、入力内容の検証を徹底することが大切です。また、LIBXML_HTML_NOIMPLIEDなどのオプションは、recoverとは独立して、パースされるHTMLの構造を調整するために使われます。
PHP DOMDocument::recoverで不正XMLをリカバリする
1<?php 2 3/** 4 * 不正なXMLをリカバリモードでパースするサンプル関数。 5 * 6 * DOMDocument::recover プロパティは、XML文書をパースする際に「リカバリモード」を 7 * 有効にするかどうかを制御します。 8 * リカバリモードを有効にすると、整形式ではない (well-formedではない) XMLに対しても、 9 * 構文エラーを抑制し、可能な限りDOMツリーを構築しようと試みます。 10 * これは、Webサービスからの不完全なレスポンスや、手動で作成されたXMLを柔軟に 11 * 扱いたい場合に役立ちます。 12 * 13 * @param string $xmlString パースするXML文字列。 14 * @param bool $enableRecovery リカバリモードを有効にするか (true) 無効にするか (false)。 15 * @return DOMDocument|null パースされたDOMDocumentオブジェクト、またはパースに失敗した場合はnull。 16 */ 17function parseXmlWithRecovery(string $xmlString, bool $enableRecovery): ?DOMDocument 18{ 19 // libxmlのエラーを内部で処理し、警告が画面に表示されないようにします。 20 // これにより、recoverプロパティの効果がより明確になります。 21 libxml_use_internal_errors(true); 22 23 $dom = new DOMDocument('1.0', 'UTF-8'); 24 25 // DOMDocument::recover プロパティを設定します。 26 // true: 不正なXMLも可能な限りパースを試みる (エラー抑制)。 27 // false: 整形式でないXMLはパースエラーとなり、多くの場合falseを返します。 28 $dom->recover = $enableRecovery; 29 30 // XML文字列を読み込みます。 31 $success = $dom->loadXML($xmlString); 32 33 $errors = libxml_get_errors(); 34 if (!empty($errors)) { 35 echo "--- Libxml Errors (Recover Mode " . ($enableRecovery ? "ON" : "OFF") . ") ---" . PHP_EOL; 36 foreach ($errors as $error) { 37 // エラー情報を出力します。リカバリモードでも内部的にはエラーが検出されることがあります。 38 echo "Error: " . trim($error->message) . " (line " . $error->line . ")" . PHP_EOL; 39 } 40 echo "-----------------------------------------------------" . PHP_EOL; 41 libxml_clear_errors(); // エラーバッファをクリアします。 42 } 43 44 if (!$success) { 45 return null; // パースに失敗した場合はnullを返します。 46 } 47 48 // 出力時にXMLを整形するための設定。 49 $dom->formatOutput = true; 50 return $dom; 51} 52 53// 意図的に不正なXML文字列の例 54// - <item>タグが閉じられていない。 55// - <another-root>がルート要素<root>の兄弟要素として存在し、XMLの整形式性に違反している。 56$badXml = <<<XML 57<?xml version="1.0" encoding="UTF-8"?> 58<root> 59 <item>First item content 60 <item>Second item content</item> 61 <another-root> 62 <data>This is not allowed as a sibling of the main <root> element.</data> 63 </another-root> 64</root> 65XML; 66 67// --- 1. リカバリモードを無効にした場合 (DOMDocument::recover = false) --- 68echo "--- 1. Attempting to parse XML with DOMDocument::recover = false (default behavior) ---" . PHP_EOL; 69$domWithoutRecovery = parseXmlWithRecovery($badXml, false); 70 71if ($domWithoutRecovery) { 72 echo "XML parsing without recovery was unexpectedly successful. Output:" . PHP_EOL; 73 echo $domWithoutRecovery->saveXML() . PHP_EOL; 74} else { 75 echo "XML parsing without recovery failed as expected due to malformed XML." . PHP_EOL; 76} 77echo PHP_EOL; 78 79// --- 2. リカバリモードを有効にした場合 (DOMDocument::recover = true) --- 80echo "--- 2. Attempting to parse XML with DOMDocument::recover = true ---" . PHP_EOL; 81$domWithRecovery = parseXmlWithRecovery($badXml, true); 82 83if ($domWithRecovery) { 84 echo "XML parsing with recovery successful. Outputting recovered XML:" . PHP_EOL; 85 // リカバリモードで可能な限り修正された(またはエラーを無視して構築された)XMLが出力されます。 86 // 不正な部分が欠落したり、予期しない構造になることがあります。 87 echo $domWithRecovery->saveXML() . PHP_EOL; 88} else { 89 echo "XML parsing with recovery failed (this can happen for extremely malformed XML)." . PHP_EOL; 90} 91 92// libxmlのエラー処理をデフォルトに戻します。 93libxml_use_internal_errors(false); 94 95?>
PHPのDOMDocument::recoverプロパティは、XML文書をパースする際に「リカバリモード」を有効にするかどうかを制御します。このプロパティ自体は引数を取りませんが、真偽値(trueまたはfalse)を設定することで、その挙動を切り替えます。プロパティの現在の設定値は真偽値として取得できます。
recoverプロパティをtrueに設定すると、XMLが整形式ではない場合でも、構文エラーを抑制し、可能な限りDOMツリーを構築しようと試みます。これは、Webサービスからの不完全なレスポンスや、手動で作成された不完全なXMLデータを柔軟に処理したい場合に特に役立ちます。一方、falseに設定した場合(これがデフォルトの挙動です)は、XMLの整形式性に厳格で、エラーが発生するとパースは失敗します。
サンプルコードでは、意図的に閉じタグの欠損などがある不正なXML文字列を用意し、リカバリモードを無効にした場合と有効にした場合で、パース結果がどのように異なるかを示しています。リカバリモードが有効な場合は、不正な箇所を無視または可能な範囲で修正しながら、XML構造を読み込み、DOMDocumentオブジェクトを返していることが確認できます。また、libxml_use_internal_errors関数を使用して内部のエラーメッセージも表示することで、リカバリモード下でも内部的にはエラーが検出されつつ処理が続行されている様子を明確にしています。
DOMDocument::recoverは、整形式でないXMLでもエラーを抑制し、可能な限りDOMツリーを構築します。不完全なXMLの処理に役立ちますが、万能ではありません。全てのエラーを修正せず、意図しないDOMツリーが構築されたり、データが欠落したりする可能性があります。そのため、信頼性の低いXMLソースに限定し、パース後の結果の内容を必ず検証してください。libxml_use_internal_errorsと組み合わせることで、内部エラーを確認でき、より安全に利用可能です。