【PHP8.x】C14Nメソッドの使い方
C14Nメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
C14Nメソッドは、Dom\DocumentFragmentオブジェクトが保持するXMLノードの構造を、標準化された形式(Canonical XML)に正規化するメソッドです。
この正規化は、XMLドキュメントの意味的な内容に一切変更を加えることなく、物理的な表現を一意にすることを目的としています。例えば、XMLの記述において、空白文字の有無、属性の順序、名前空間の宣言方法などが異なっていても、内容が同じであれば同じXMLとして扱えるように、定められた規則に従って統一された形式に変換します。
主にデジタル署名やハッシュ値の計算において、XMLドキュメントの同一性を厳密に保証するために利用されます。これにより、異なるシステムや処理環境で生成されたXMLであっても、その内容が同一であれば、署名検証時などに表現の差異を吸収し、常に同じXMLとみなすことが可能になります。
本メソッドには、オプションで引数を指定できます。例えば、$exclusive引数にtrueを設定することで、排他的な正規化(Exclusive XML Canonicalization)を適用し、要素内で使用されていない名前空間の宣言を削除するなど、名前空間の扱いをより厳密に制御できます。また、$with_comments引数でコメントを含めるか否かを指定したり、$xpathや$ns_prefixes引数を利用して正規化の対象を特定のノードセットに限定したりすることも可能です。実行結果として、正規化されたXML文字列が返されます。
構文(syntax)
1<?php 2 3$dom = new DOMDocument(); 4$fragment = $dom->createDocumentFragment(); 5$element = $dom->createElement('item'); 6$element->appendChild($dom->createTextNode('content')); 7$fragment->appendChild($dom->importNode($element, true)); 8 9$canonicalOutput = $fragment->C14N(); 10 11?>
引数(parameters)
?bool $exclusive = null, ?bool $withComments = null, ?array $xpath = null, ?array $nsPrefixes = null
- bool $exclusive: trueの場合、指定されたXPath式に一致するノードのみを正規化します。falseの場合、ドキュメント全体を正規化します。
- bool $withComments: trueの場合、コメントノードも正規化に含めます。falseの場合、コメントノードは無視されます。
- array $xpath: 正規化するノードを指定するためのXPath式配列。nullの場合、ドキュメント全体が対象となります。
- array $nsPrefixes: 名前空間プレフィックスの配列。正規化時にこれらのプレフィックスのみを使用します。nullの場合、ドキュメントで使用されているすべての名前空間プレフィックスが使用されます。
戻り値(return)
string|false
このメソッドは、XML文書の断片(Dom\DocumentFragment)を標準化された形式(C14N)の文字列で返します。正規化に失敗した場合はfalseを返します。
サンプルコード
PHP: DocumentFragment C14N正規化する
1<?php 2 3/** 4 * Dom\DocumentFragment::C14N を使用してXML文書断片を正規化するサンプル関数 5 * 6 * この関数は、DOMDocumentFragmentを作成し、いくつかのノードを追加した後、 7 * C14Nメソッドの引数を変えながら正規化(Canonicalization)された 8 * XML文字列を生成し、その結果を出力します。 9 * C14Nは、論理的に等価なXML文書がバイトレベルでも同一の表現になるように 10 * 変換するためのW3C標準規格です。電子署名などで利用されます。 11 */ 12function generateCanonicalXmlFragmentExample(): void 13{ 14 // PHP 8のDOM拡張機能を使用 15 $dom = new \Dom\Document(); 16 17 // 1. DocumentFragmentを作成します。 18 // これは文書全体ではなく、XMLの一部を保持するための軽量なコンテナです。 19 $fragment = $dom->createDocumentFragment(); 20 21 // 2. フラグメントに様々なノードを追加します。 22 // コメントノード 23 $fragment->appendChild($dom->createComment(' comment ')); 24 25 // 名前空間を持つ要素 26 $parent = $dom->createElementNS('https://example.com/ns', 'ns:parent'); 27 $parent->setAttribute('attr', 'value'); 28 $fragment->appendChild($parent); 29 30 // テキストを持つ子要素 31 $child = $dom->createElement('child'); 32 $child->appendChild($dom->createTextNode('Hello World')); 33 $parent->appendChild($child); 34 35 36 // 3. C14N() メソッドを実行して正規化された文字列を取得します。 37 // 引数を変更することで、出力形式を制御できます。 38 39 // ケース1: デフォルト (exclusive: false, withComments: false) 40 // コメントは除去され、名前空間の定義はそのまま出力されます。 41 echo "--- Default C14N (non-exclusive, no comments) ---\n"; 42 $defaultResult = $fragment->C14N(); 43 echo $defaultResult . "\n\n"; 44 45 // ケース2: コメントを含む (withComments: true) 46 echo "--- C14N with comments ---\n"; 47 $withCommentsResult = $fragment->C14N(false, true); 48 echo $withCommentsResult . "\n\n"; 49 50 // ケース3: 排他的正規化 (exclusive: true) 51 // その要素のコンテキストで実際に使用されている名前空間のみが出力されます。 52 echo "--- Exclusive C14N ---\n"; 53 $exclusiveResult = $fragment->C14N(true, false); 54 echo $exclusiveResult . "\n"; 55} 56 57// 関数を実行して結果を表示 58generateCanonicalXmlFragmentExample(); 59
このPHPサンプルコードは、Dom\DocumentFragment::C14Nメソッドを使い、XML文書の一部分を正規化する方法を示しています。正規化(Canonicalization)とは、論理的に同じ意味を持つXMLが、バイトレベルで完全に同一の文字列表現になるよう変換するW3C標準のルールのことで、主に電子署名の検証などで利用されます。
コードでは、まずDocumentFragmentオブジェクトを作成し、コメントや名前空間を持つ要素ノードを追加して、XMLの断片を構築します。DocumentFragmentは、文書全体ではなく、その一部を保持するための軽量なコンテナとして機能します。
その後、この断片に対してC14Nメソッドを異なる引数で呼び出し、出力結果を比較しています。第一引数の$exclusiveをtrueにすると「排他的正規化」となり、その断片内で実際に使用されている名前空間定義のみが出力されます。第二引数の$withCommentsをtrueにすると、出力にコメントが含まれます。引数を指定しない場合は、コメントは除去され、排他的ではない通常の正規化が行われます。このメソッドは、処理に成功すると正規化されたXML文字列を返し、失敗した場合はfalseを返します。このように、引数を調整することで、要件に応じた形式でXMLを標準化できます。
C14Nメソッドは、XMLを論理的に同じ意味を持つ統一されたバイト表現(正規化)に変換する専門的な機能です。これは主にXML電子署名でデータが改ざんされていないか検証する目的で利用されます。引数exclusiveをtrueにすると「排他的正規化」となり、そのXML断片で実際に使われている名前空間だけが出力されます。この設定は出力結果に大きく影響するため、利用する規格の要件に合わせて正しく選択することが重要です。また、このメソッドは処理に失敗するとfalseを返すため、実際のプログラムでは戻り値が文字列であることを確認するエラー処理を必ず記述してください。