【PHP8.x】Dom\EntityReference::C14NFile()メソッドの使い方
C14NFileメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
『C14NFileメソッドは、Dom\EntityReferenceオブジェクトが表すエンティティ参照ノード、およびその子孫ノードを正規化し、その結果を指定されたファイルに書き込む処理を実行するメソッドです。正規化(Canonicalization)とは、XML文書の表現形式を、決められた一貫性のあるルールに基づいて統一された形式に変換する処理を指します。例えば、属性の順序や空白の扱いなどを統一することで、見た目上の記述が異なっていても、論理的に同じ内容を持つXML文書を比較できるようになります。このメソッドの第一引数には、出力先のファイルパスを文字列で指定します。続く引数で、排他的正規化を行うか、コメントを含めるかといった、正規化の具体的なルールを真偽値で制御することが可能です。処理が成功した場合にはファイルに書き込まれたバイト数を整数で返し、失敗した場合にはfalseを返します。この機能は、XMLデータのデジタル署名や、異なるシステム間でXMLデータの一貫性を厳密に検証する必要がある場合などに特に重要となります。
構文(syntax)
1public Dom\EntityReference::C14NFile( 2 string $uri, 3 bool $exclusive = false, 4 bool $withComments = false, 5 ?array $xpath = null, 6 ?array $nsPrefixes = null 7): int|false
引数(parameters)
string $uri, bool $exclusive = false, bool $withComments = false, ?array $xpath = null, ?array $nsPrefixes = null
- string $uri: 正規化するXMLドキュメントのURIまたはDOMDocumentオブジェクト
- bool $exclusive = false: trueに設定すると、排他的な名前空間カノニカル化が有効になります
- bool $withComments = false: trueに設定すると、コメントもカノニカル化に含めます
- ?array $xpath = null: カノニカル化するノードを絞り込むためのXPathクエリの配列
- ?array $nsPrefixes = null: 名前空間プレフィックスのマッピングを指定する連想配列
戻り値(return)
int|false
このメソッドは、エンティティ参照を正規化してファイルに保存する際の成功または失敗を示す整数値、あるいは操作に失敗した場合は false を返します。
サンプルコード
PHP Dom\EntityReference::C14NFileでエンティティ参照を正規化する
1<?php 2 3/** 4 * Dom\EntityReference::C14NFile メソッドの使用例を示します。 5 * 6 * この関数は、XMLドキュメント内のエンティティ参照ノードを検索し、 7 * その参照が指す内容を C14N (Canonical XML) 形式でファイルに出力します。 8 * C14Nの仕様により、エンティティ参照自体ではなく、その参照が展開された 9 * 内容が正規化されます。 10 * 11 * @param string $xmlString 正規化するXMLコンテンツの文字列。 12 * @param string $outputFile 正規化されたXMLを書き込むファイルパス。 13 * @param bool $withComments 正規化された出力にコメントを含めるかどうか。 14 * @return void 15 */ 16function demonstrateC14NFileForEntityReference( 17 string $xmlString, 18 string $outputFile, 19 bool $withComments = false 20): void { 21 // Dom\Document のインスタンスを作成します。 22 $dom = new Dom\Document(); 23 24 // XMLをロードします。 25 // LIBXML_NOENT フラグは非常に重要です。これを指定することで、 26 // &myEntity; のようなエンティティ参照をパース時に展開せず、 27 // Dom\EntityReference ノードとしてドキュメントツリーに保持させます。 28 // これがないと、エンティティ参照は自動的にテキストに展開され、 29 // Dom\EntityReference ノードとして取得できなくなります。 30 if (!$dom->loadXML($xmlString, LIBXML_NOENT)) { 31 echo "エラー: XMLのロードに失敗しました。\n"; 32 return; 33 } 34 35 // ドキュメントツリー全体を探索し、最初に見つかった Dom\EntityReference ノードを取得します。 36 // ここでは幅優先探索 (BFS) に近い方法でノードを探索します。 37 $entityReferenceNode = null; 38 $queue = [$dom]; // 探索キューをドキュメントノードで初期化 39 40 while (!empty($queue)) { 41 $node = array_shift($queue); // キューの先頭からノードを取り出す 42 if ($node instanceof Dom\EntityReference) { 43 $entityReferenceNode = $node; 44 break; // Dom\EntityReference ノードが見つかったので探索を終了 45 } 46 // 現在のノードに子ノードがある場合、それらをキューに追加して後で探索します。 47 if ($node->hasChildNodes()) { 48 foreach ($node->childNodes as $child) { 49 $queue[] = $child; 50 } 51 } 52 } 53 54 if (!$entityReferenceNode) { 55 echo "エラー: XML内から Dom\\EntityReference ノードが見つかりませんでした。\n"; 56 echo "XMLコンテンツに `<!ENTITY ...>` 定義と `&entityName;` 形式の参照があるか、\n"; 57 echo "または `loadXML()` の際に `LIBXML_NOENT` フラグが正しく適用されているか確認してください。\n"; 58 return; 59 } 60 61 echo "--- Dom\\EntityReference::C14NFile の実行 --- \n"; 62 echo "対象ノード: Dom\\EntityReference (ノード名: '{$entityReferenceNode->nodeName}')\n"; 63 echo "出力先ファイル: '{$outputFile}'\n"; 64 echo "コメントを含める: " . ($withComments ? 'はい' : 'いいえ') . "\n"; 65 66 // Dom\EntityReference::C14NFile メソッドを呼び出し、正規化されたXMLをファイルに書き込みます。 67 // 68 // C14N (Canonical XML) の仕様に基づき、ここで出力される内容は 69 // '&myEntity;' というエンティティ参照自体ではなく、その参照が指す実体 70 // (例: "This is some entity content.") が展開され、正規化されたものです。 71 // 72 // 引数: 73 // $uri: 出力するファイルのパス (string) 74 // $exclusive: 排他的正規化モードを使用するかどうか (bool, falseで通常のC14N) 75 // $withComments: コメントを含めるかどうか (bool) 76 // $xpath: (オプション) 特定のノードセットを対象とする XPath 式の配列 (nullで全ノード) 77 // $nsPrefixes: (オプション) 特定の名前空間プレフィックスの配列 (nullで全て) 78 $bytesWritten = $entityReferenceNode->C14NFile($outputFile, false, $withComments, null, null); 79 80 if ($bytesWritten === false) { 81 echo "エラー: 正規化されたXMLをファイル '{$outputFile}' に書き込めませんでした。\n"; 82 } else { 83 echo "成功: '{$outputFile}' に {$bytesWritten} バイトを書き込みました。\n"; 84 echo "\n--- '{$outputFile}' の内容 ---\n"; 85 echo htmlspecialchars(file_get_contents($outputFile)); // 出力内容をHTMLエンコードして表示 86 echo "--------------------------\n"; 87 } 88 89 // 後処理として、生成されたファイルを削除します。 90 if (file_exists($outputFile)) { 91 unlink($outputFile); 92 echo "ファイル '{$outputFile}' を削除しました。\n"; 93 } 94} 95 96// ----------------------------------------------------------------------------- 97// サンプルコードの実行 98// ----------------------------------------------------------------------------- 99 100// 正規化するXMLコンテンツの定義。 101// <!DOCTYPE> 宣言で 'myEntity' と 'anotherEntity' というエンティティを定義し、 102// <data> および <info> 要素内でそれらを参照しています。 103$xmlContent = <<<XML 104<?xml version="1.0" encoding="UTF-8"?> 105<!DOCTYPE root [ 106 <!ENTITY myEntity "これはエンティティの内容です。"> 107 <!ENTITY anotherEntity "別の内容 & 特殊文字。"> 108]> 109<root> 110 <data>こんにちは、&myEntity; 世界!</data> 111 <info>ここには &anotherEntity; があります。</info> 112 <!-- これは正規化テスト用のコメントです --> 113</root> 114XML; 115 116$outputFilePath = 'entity_reference_normalized_output.xml'; 117 118// --- 例1: コメントを含めずにエンティティ参照の内容を正規化 --- 119echo "=== 例1: コメントを含めないC14Nの実行 ===\n"; 120demonstrateC14NFileForEntityReference($xmlContent, $outputFilePath, false); 121 122echo "\n"; // 出力の区切り 123 124// --- 例2: コメントを含めてエンティティ参照の内容を正規化 --- 125// 例1で出力されたファイルを上書きします。 126echo "=== 例2: コメントを含めるC14Nの実行 ===\n"; 127demonstrateC14NFileForEntityReference($xmlContent, $outputFilePath, true); 128 129?>
PHPの Dom\EntityReference::C14NFile メソッドは、XMLドキュメント内のエンティティ参照ノードが指す内容を、C14N (Canonical XML) と呼ばれる標準化された形式で指定のファイルに出力します。C14Nは、XMLの構文上の差異(空白や属性の順序など)を吸収し、論理的に同じXMLを常に同じバイト列として表現するための仕様です。このメソッドでは、エンティティ参照そのものではなく、その参照が展開された実体の内容が正規化の対象となります。
サンプルコードでは、XMLを読み込む際に LIBXML_NOENT フラグを使用している点が重要です。このフラグによって、&myEntity; のようなエンティティ参照が自動展開されず、Dom\EntityReference オブジェクトとしてドキュメントツリーに保持されます。その後にこのオブジェクトを探索し、C14NFile メソッドを呼び出しています。
引数 $uri は正規化されたXMLを書き出すファイルパスを指定します。$exclusive は排他的C14N形式を使用するかどうかを真偽値で指定し、通常は false を指定します。$withComments は出力にXMLコメントを含めるかを真偽値で指定します。オプションの $xpath や $nsPrefixes は、特定のノードや名前空間を対象とする場合に利用できます。
戻り値は、処理が成功した場合はファイルに書き込まれたバイト数を整数値で返します。ファイル書き込みの失敗など、エラーが発生した場合は false を返します。このメソッドは、XMLの署名や比較など、XMLの同一性を厳密に扱う必要がある場面で役立ちます。
Dom\EntityReference::C14NFileメソッドを使用する際は、まずDom\Document::loadXML()でLIBXML_NOENTフラグを必ず指定してください。このフラグがないと、エンティティ参照が自動的に展開され、Dom\EntityReferenceノードとして取得できず、本メソッドを呼び出せなくなります。また、本メソッドはエンティティ参照ノードに対して呼び出しますが、正規化されるのは参照そのものではなく、その参照が指すXML実体の内容がC14N形式でファイルに出力されます。メソッドの実行に失敗するとfalseが返されるため、ファイルの書き込み権限がない場合などに備え、必ず戻り値をチェックし適切なエラー処理を実装してください。指定する出力ファイルパスの書き込み権限にも注意が必要です。
PHP Dom::C14NFileで実体参照を正規化・コピーする
1<?php 2 3/** 4 * Dom\EntityReference::C14NFile メソッドの使用例を示します。 5 * 6 * このメソッドは、指定された実体参照ノード(例: &entity_name; の形式)をXML正規化し、 7 * その結果を指定されたファイルに書き込みます。 8 * キーワード 'php cp' (コピー) に関連付けて、XMLの正規化された内容をファイルに書き出す動作を示します。 9 * 10 * @param string $outputFile 正規化されたXMLを書き込むファイルのパス 11 */ 12function demonstrateC14NFileForEntityReference(string $outputFile): void 13{ 14 // 1. DOMDocumentを初期化します。 15 // XMLバージョンとエンコーディングを指定し、読みやすい形式で出力するように設定します。 16 $dom = new DOMDocument('1.0', 'UTF-8'); 17 $dom->preserveWhiteSpace = false; 18 $dom->formatOutput = true; 19 20 // 2. DTD (Document Type Definition) を含むXML文字列をロードします。 21 // これにより、'copyright' という名前の実体参照が定義され、DOMパーサーに認識されます。 22 $xmlContentWithDTD = <<<XML 23<!DOCTYPE root [ 24 <!ENTITY copyright "© MyCompany 2023. All rights reserved."> 25]> 26<root> 27 <introduction>この文書は著作権情報を含みます。</introduction> 28</root> 29XML; 30 31 // XMLをロードします。LIBXML_NOENT フラグは実体参照を展開しないように指示しますが、 32 // PHPのDOMの挙動により、DOMツリーにDOMEntityReferenceノードが直接現れることは稀です。 33 // そのため、ここでは createEntityReference() を使用してノードを明示的に作成します。 34 $dom->loadXML($xmlContentWithDTD, LIBXML_NOENT); 35 36 // 3. 'copyright' という名前のDOMEntityReferenceノードを作成します。 37 // このノードは、上で定義したDTDの実体を参照します。 38 // これは、PHPのDOMにおけるDOMEntityReferenceクラスのインスタンスです。 39 // プログラミング言語リファレンス情報ではDom\EntityReferenceと記載されていますが、 40 // 実際のPHPのクラス名はDOMEntityReferenceです。 41 $entityReferenceNode = $dom->createEntityReference('copyright'); 42 43 // 4. 作成した実体参照ノードをドキュメントツリー内の適切な位置に追加します。 44 // ここでは、<root>要素の末尾に追加します。 45 $rootElement = $dom->getElementsByTagName('root')->item(0); 46 if (null === $rootElement) { 47 echo "エラー: <root>要素が見つかりませんでした。XMLの構造を確認してください。\n"; 48 return; 49 } 50 $rootElement->appendChild($entityReferenceNode); 51 52 // 5. Dom\EntityReference (DOMEntityReference) オブジェクトの C14NFile メソッドを呼び出します。 53 // このメソッドはDOMNodeクラスのメソッドであり、DOMEntityReferenceはDOMNodeを継承しているため、 54 // このメソッドを呼び出すことができます。 55 // C14NFileは、実体参照ノード自体(©right; の形式)を正規化して出力します。 56 // 'php cp' のキーワードに合わせ、XMLの正規化された内容をファイルにコピーする操作を示します。 57 echo "実体参照ノードの正規化された内容をファイルにコピーしています: " . $outputFile . "\n"; 58 $result = $entityReferenceNode->C14NFile( 59 $outputFile, 60 false, // $exclusive: 排他的正規化を適用しない (falseは包括的正規化) 61 false // $withComments: コメントを含めない 62 // $xpath, $nsPrefixes: 今回は使用しないためデフォルト値 (null) 63 ); 64 65 // 6. 処理結果を表示します。 66 if (false === $result) { 67 echo "エラー: C14NFileの実行に失敗しました。DTDでの実体定義やノードの配置を確認してください。\n"; 68 } else { 69 echo "成功: " . $result . " バイトがファイルに書き込まれました。\n"; 70 echo "生成されたファイル '" . $outputFile . "' の内容を確認してください。\n"; 71 72 // 生成されたファイルの内容をコンソールにも出力し、確認しやすくします。 73 echo "\n--- " . $outputFile . " の内容 ---\n"; 74 echo file_get_contents($outputFile); 75 echo "\n---------------------------\n"; 76 } 77} 78 79// サンプルコードを実行するために、出力ファイル名を指定します。 80// スクリプトと同じディレクトリにファイルが作成されます。 81$outputFileName = __DIR__ . '/c14n_entity_reference_output.xml'; 82demonstrateC14NFileForEntityReference($outputFileName);
PHPのDom\EntityReference::C14NFileメソッドは、XML文書内の実体参照ノードをXML正規化し、その結果を指定されたファイルに書き出すための機能です。実体参照とは、&entity_name;のようにXML文書内で定義され、特定のテキストやマークアップを参照する仕組みを指します。このメソッドは、DOMツリー内の実体参照ノードに対し、XMLの標準的な出力形式であるC14N(Canonical XML)変換を適用し、その結果を引数$uriで指定されたファイルパスに保存します。
サンプルコードでは、まずcopyrightという名前の実体参照を定義したXML文書を準備し、その実体参照ノードをDOMツリー内に作成・追加しています。その後、この実体参照ノードに対してC14NFileメソッドを呼び出し、正規化された実体参照のコンテンツを外部ファイルに書き出しています。引数$exclusiveは排他的正規化を行うか、$withCommentsはコメントを含めるかを制御します。また、$xpathや$nsPrefixesは、正規化の対象範囲を絞り込む際に使用されます。このメソッドの戻り値は、書き込まれたバイト数を示す整数値か、処理が失敗した場合にはfalseを返します。キーワード「php cp」に照らし合わせると、この操作はXMLの実体参照部分を正規化し、その結果を別のファイルに「コピー」するような動作として理解できます。これにより、XMLデータの標準化された形式を簡単にファイルとして出力できます。
このメソッドを使う際、リファレンス情報のDom\EntityReferenceは、実際のPHPクラス名がDOMEntityReferenceである点にご注意ください。XMLの実体参照ノードは、DOMDocument::createEntityReference()で明示的に作成し、DTDで定義されている必要があります。C14NFileはDOMNodeを継承するクラスで利用可能です。メソッドは成功時に書き込みバイト数、失敗時にfalseを返すため、必ず結果を確認しエラーハンドリングを行ってください。出力ファイルへの書き込み権限や、既存ファイルの上書きにも注意が必要です。正規化のオプション引数(排他的正規化やコメント含めるかなど)は出力内容に影響するため、用途に応じて適切に設定してください。