【PHP8.x】DOMEntity::C14N()メソッドの使い方
C14Nメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
C14Nメソッドは、DOMEntityノードをCanonical XML形式でシリアライズするメソッドです。DOMEntityは、XMLドキュメント内でエンティティを参照するノードを表します。C14Nメソッドを使用することで、エンティティノードの内容を標準化されたXML形式の文字列として取得できます。
このメソッドは、XMLドキュメントのデジタル署名や、異なるシステム間でのXMLデータの整合性検証において重要な役割を果たします。Canonical XMLは、XMLドキュメントの論理的な意味内容を変えずに、表現形式を統一することを目的としています。これにより、空白、属性の順序、名前空間のプレフィックスなどの違いによって、XMLドキュメントが異なると判断されるのを防ぎます。
C14Nメソッドは、エンティティノードをCanonical XML形式に変換することで、エンティティの内容が一意に表現されることを保証します。これにより、エンティティの内容に基づく処理や比較を、環境に依存せずに行うことが可能になります。例えば、あるXMLドキュメントのエンティティの内容を別のシステムで検証する際に、C14Nメソッドを使用することで、両方のシステムで同じ結果が得られることを保証できます。
このメソッドは、XML処理において高度な制御が必要な場合に特に有用です。標準化されたXML形式を用いることで、セキュリティリスクを低減し、相互運用性を高めることができます。DOMEntityノードのC14Nメソッドを使用することで、XMLドキュメントの特定の部分を標準化された形式で抽出し、様々な目的に利用することができます。
構文(syntax)
1DOMEntity::C14N( 2 ?string $exclusive = null, 3 bool $withComments = false, 4 ?array $namespaces = null, 5 ?string $prefix = null 6): string|false
引数(parameters)
bool $exclusive = false, bool $withComments = false, ?array $xpath = null, ?array $nsPrefixes = null
- bool $exclusive = false: 包含するエンティティの範囲を排他的にするかどうかを示すブール値。
trueの場合、指定されたノードのみが対象となります。 - bool $withComments = false: コメントノードを含めるかどうかを示すブール値。
- ?array $xpath = null: 正規化の対象とするノードをXPath式で指定する配列。
nullの場合はすべてのノードが対象となります。 - ?array $nsPrefixes = null: 名前空間のプレフィックスを正規化の対象として指定する配列。
nullの場合はすべての名前空間が対象となります。
戻り値(return)
bool
この C14N メソッドは、エンティティの正規化が成功したかどうかを示す真偽値(boolean)を返します。正規化が成功した場合は true を、失敗した場合は false を返します。
サンプルコード
PHP XML DOMEntity::C14Nでエンティティ正規化する
1<?php 2 3/** 4 * DOMEntity::C14N() を使用してXMLエンティティを正規化するサンプル関数 5 * 6 * この関数は、DTD(文書型定義)を含むXML文字列を解析し、 7 * 特定のエンティティノードを取得して、その内容を正規化(C14N)します。 8 * 正規化された文字列は、XMLの論理的な意味を保ったまま一貫した形式に変換されるため、 9 * デジタル署名やデータの比較に利用されます。 10 */ 11function demonstrateDomEntityC14N(): void 12{ 13 // DTDでエンティティが定義されたXML文字列を用意します。 14 // 'myEntity' という名前のエンティティに '<inner>Entity Content</inner>' という内容を定義しています。 15 $xmlString = <<<XML 16<?xml version="1.0" encoding="UTF-8"?> 17<!DOCTYPE root [ 18 <!ENTITY myEntity "<inner attr='value'>Entity Content</inner>"> 19]> 20<root> 21 <element>&myEntity;</element> 22</root> 23XML; 24 25 // DOMDocumentオブジェクトを生成します。 26 $dom = new DOMDocument(); 27 28 // XML文字列を読み込みます。 29 if (!$dom->loadXML($xmlString)) { 30 echo "XMLの読み込みに失敗しました。"; 31 return; 32 } 33 34 // ドキュメントのDOCTYPEノードを取得します。 35 $doctype = $dom->doctype; 36 37 // DOCTYPEが存在し、エンティティが定義されているか確認します。 38 if ($doctype && $doctype->entities) { 39 // 'myEntity' という名前のエンティティノード (DOMEntity) を取得します。 40 $entity = $doctype->entities->getNamedItem('myEntity'); 41 42 if ($entity instanceof DOMEntity) { 43 // DOMEntityオブジェクトに対して C14N() メソッドを呼び出し、正規化された文字列を取得します。 44 // 失敗した場合は false が返ります。 45 $canonicalizedString = $entity->C14N(); 46 47 if ($canonicalizedString !== false) { 48 echo "エンティティ 'myEntity' の正規化 (C14N) された文字列:" . PHP_EOL; 49 echo $canonicalizedString . PHP_EOL; 50 } else { 51 echo "エンティティの正規化に失敗しました。" . PHP_EOL; 52 } 53 } else { 54 echo "エンティティ 'myEntity' が見つかりませんでした。" . PHP_EOL; 55 } 56 } else { 57 echo "DTDまたはエンティティ定義が見つかりませんでした。" . PHP_EOL; 58 } 59} 60 61// サンプル関数を実行します。 62demonstrateDomEntityC14N(); 63
DOMEntity::C14N()は、XML文書のDTD(文書型定義)で定義されたエンティティの内容を、W3Cが定める公式ルールに従って「正規化(C14N)」するためのメソッドです。正規化とは、XMLの見た目(例えば属性の順序や空白の量など)が異なっていても、論理的に同じ内容であれば常に同一の文字列に変換する処理のことです。これにより、データの一貫性が保証されるため、デジタル署名やデータの比較などに利用されます。
サンプルコードでは、まずDTD内で<inner>要素を含むmyEntityというエンティティを定義したXML文字列を用意します。次にDOMDocumentオブジェクトでXMLを解析し、getNamedItem()を使って目的のDOMEntityオブジェクトを取得します。そして、そのオブジェクトのC14N()メソッドを呼び出すことで、エンティティの内容が正規化された文字列に変換されます。
このメソッドは、排他的正規化の指定やコメントの有無などを引数で制御できますが、この例では引数を省略し、標準的なルールで処理しています。メソッドは成功すると正規化された文字列を返し、失敗した場合はfalseを返します。サンプルではこの戻り値を確認し、正規化された結果を出力しています。
DOMEntity::C14N()メソッドは、XMLのDTD(文書型定義)内で定義されたエンティティを正規化する機能です。このため、サンプルコードのようにDOCTYPE宣言とエンティティ定義がXML内に存在することが前提となります。メソッドは処理に失敗するとfalseを返すため、戻り値のチェックは!== falseのように厳密な比較で行う必要があります。また、外部のXMLデータを扱う際は、意図しない外部エンティティ読み込みによる脆弱性を防ぐため、処理の前にlibxml_disable_entity_loader(true)を呼び出してセキュリティを確保することが重要です。
PHP 8 DOMEntity::C14N() でXMLを正規化する
1<?php 2 3/** 4 * XML文字列をCanonical XML 1.1 (C14N 1.1) 形式に正規化します。 5 * 6 * Canonical XML (正規化XML) は、空白や属性の順序などが異なる 7 * 論理的に等価な2つのXML文書から、バイト単位で同一の表現を生成するための標準です。 8 * これにより、XMLデータの署名や比較が容易になります。 9 * 10 * @param string $xmlString 正規化するXML文字列 11 * @return string|false 正規化されたXML文字列。失敗した場合は false。 12 */ 13function canonicalizeXmlWithC14N11(string $xmlString): string|false 14{ 15 // DOMDocumentオブジェクトを作成します。 16 $dom = new DOMDocument(); 17 18 // XMLを読み込む際に、不要な空白を保持しないように設定します。 19 $dom->preserveWhiteSpace = false; 20 21 // 与えられたXML文字列をDOMオブジェクトに読み込みます。 22 if (!$dom->loadXML($xmlString)) { 23 // XMLの読み込みに失敗した場合 24 return false; 25 } 26 27 // DOMNode::C14N() メソッドを使用してXML文書を正規化します。 28 // PHP 8.0以降では、第5引数 (mode) に定数を指定することで 29 // 使用する正規化のバージョンを選択できます。 30 // 31 // 引数の説明: 32 // 1. $exclusive: 排他的正規化を行うか (false = 通常の正規化) 33 // 2. $withComments: コメントを含めるか (false = コメントを削除) 34 // 3. $xpath: 正規化対象を絞り込むXPathクエリ (null = 文書全体) 35 // 4. $nsPrefixes: 排他的正規化で利用する名前空間プレフィックスの配列 (null) 36 // 5. $mode: 正規化のバージョン (XML_C14N_1_1 を指定) 37 return $dom->C14N( 38 false, 39 false, 40 null, 41 null, 42 XML_C14N_1_1 43 ); 44} 45 46// 正規化対象のXMLデータ 47// 属性の順序がバラバラで、余分な空白や改行、コメントが含まれています。 48$originalXml = <<<XML 49<?xml version="1.0" encoding="UTF-8"?> 50<!-- Sample XML document --> 51<document status="active" version="1.0" > 52 <message>Hello, C14N 1.1!</message> 53</document> 54XML; 55 56// 関数を呼び出してXMLを正規化します。 57$canonicalizedXml = canonicalizeXmlWithC14N11($originalXml); 58 59if ($canonicalizedXml !== false) { 60 echo "--- Original XML ---" . PHP_EOL; 61 echo $originalXml . PHP_EOL . PHP_EOL; 62 63 echo "--- Canonicalized XML (C14N 1.1) ---" . PHP_EOL; 64 // 出力結果: 65 // <document status="active" version="1.0"><message>Hello, C14N 1.1!</message></document> 66 // コメントや余分な空白が除去され、属性が特定の順序で並び替えられます。 67 echo $canonicalizedXml . PHP_EOL; 68} else { 69 echo "Failed to canonicalize XML." . PHP_EOL; 70} 71
DOMNode::C14N()メソッドは、XML文書を「Canonical XML(正規化XML)」という世界共通の標準形式に変換します。正規化XMLは、属性の記述順や空白の量といった本質的ではない違いを吸収し、論理的に同じ内容を持つXML文書から、常にバイト単位で同一の文字列表現を生成するためのルールです。これにより、XMLデータにデジタル署名を付与したり、二つの文書が同一であるかを厳密に比較したりする際に役立ちます。
このサンプルコードでは、まずXML文字列をDOMDocumentオブジェクトとして読み込み、そのオブジェクトに対してC14N()メソッドを呼び出しています。このメソッドは、第1引数で排他的正規化を行うか、第2引数でコメントを含めるかなどを指定できます。PHP 8.0からは第5引数が追加され、正規化のバージョンを指定できるようになりました。この例ではXML_C14N_1_1定数を渡し、Canonical XML 1.1の仕様で処理を行っています。
メソッドは、処理に成功すると正規化されたXML文字列を返し、失敗した場合はfalseを返します。実行結果を見ると、元のXMLにあったコメントや余分な空白が取り除かれ、属性が特定の順序で整列された、一貫性のある文字列が生成されていることが確認できます。
このコードで使われているC14Nメソッドの第5引数$modeは、PHP 8.0から追加された機能です。そのため、古いPHP環境ではエラーになる点に注意が必要です。この引数でXML_C14N_1_1を指定しないと、古い仕様のC14N 1.0が適用されるため、目的のバージョンを明示することが重要です。また、loadXML関数は不正な形式のXML文字列を読み込むと失敗しますので、サンプルのように必ず戻り値を確認し、エラー処理を実装してください。コメントを残したい場合は第2引数をtrueに変更します。正規化後のXMLは、データ比較を目的として改行や空白が除去された1行の文字列として出力されます。