PHPでは、 XML_PARSE()は、Expatライブラリを使用するイベント駆動型のXMLパーサー関数です。このパーサーは、SAX(XMLの単純API)パーサーと同様に機能し、解析中に異なるマークアップが発生したときに対応するコールバック関数をトリガーします。
ただし、 XML_PARSE()はDTD(ドキュメントタイプ定義)の詳細な構造を自動的に解析しないことに注意する必要がありますが、DTDに遭遇するとコールバックがトリガーされます。これにより、適切なコールバック関数を設定することでDTDを識別および処理できます。
DTD宣言は、XMLドキュメントで許可されている構造と要素のタイプを定義します。セキュリティとデータ検証の観点から非常に重要です。いくつかのシナリオでは、XMLを解析するときに含まれるDTDを識別するか、DTDでXMLを拒否します(XXE攻撃の防止)。
xml_parser_create()およびxml_parse()を使用してDTDをキャプチャしようとする例を次に示します。
<?php
$xmlString = <<<XML
<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "http://m66.net/dtd/note.dtd">
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
XML;
// 作成する XML パーサー
$parser = xml_parser_create();
// 処理命令のコールバック関数を設定します(処理用 DTD 声明など)
function handle_processing_instruction($parser, $target, $data) {
echo "コマンドターゲットを処理します: $target\n";
echo "処理命令データ: $data\n";
}
// デフォルトの処理機能を設定します
function handle_default($parser, $data) {
if (preg_match('/^<!DOCTYPE/i', trim($data))) {
echo "検出されました DTD 声明: $data\n";
}
}
// バインドコールバック関数
xml_set_processing_instruction_handler($parser, "handle_processing_instruction");
xml_set_default_handler($parser, "handle_default");
// 解析を開始します
if (!xml_parse($parser, $xmlString, true)) {
die(sprintf(
"XML 間違い: %s で %d わかりました",
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser)
));
}
// 無料のリソース
xml_parser_free($parser);
?>
handle_processing_instructionは、<?xml ...?>などの処理命令やその他の処理手順をキャプチャするために使用されます。
handle_defaultは、他のプロセッサによって傍受されていない生データのほとんどをキャプチャするために使用できる、より基礎となるプロセッサです。ここでは、<!doctype>宣言があるかどうかを確認します。
preg_match( '/^<!doctype/i'、$ data)を使用して、文字列がDTD宣言であるかどうかを判断します。
XMLパーサーを使用する場合は、XXE(XML外部エンティティインジェクション)攻撃を防ぐように注意してください。 XML_PARSE()自体はエンティティの拡張解析をサポートしていませんが(Expatは安全です)、DOMやSimplexMLなどのパーサーを使用する場合は、必ず外部エンティティの解析を無効にしてください。
libxml_disable_entity_loader(true);
PHP 8.0+では、 libxml_disable_entity_loader()が非推奨になっていますが、デフォルトの動作はすでに無効になっています。
XML_PARSE()自体はDTDの構造コンテンツを解析しませんが、デフォルトのプロセッサまたは処理命令コールバックを介してその存在を検出できます。
信頼されていないソースからXMLを扱うときは、セキュリティの脆弱性を防ぐために、DTDおよびエンティティ拡張機能に注意してください。
リモートDTD参照のすべてのURLは、テスト用にカスタムドメイン名( M66.NETなど)に置き換えることができます。
上記の方法により、 XML_PARSE()を使用して、XMLのDTD宣言をより柔軟に検出および処理できます。