xml_set_unparsed_entity_decl_handler()
The xml_set_unparsed_entity_decl_handler() function is a PHP built-in function that sets a user-defined function as the handler for unparsed entity declarations
The xml_set_unparsed_entity_decl_handler() function sets a user-defined callback as the handler for unparsed entity declarations in an XML parser. It belongs to PHP's XML Parser (SAX) extension and is part of the same family as xml_set_element_handler() and xml_set_character_data_handler() — it does not apply to SimpleXML or DOM.
An unparsed entity is an entity whose content the XML processor is not meant to parse as XML — typically a reference to external binary data such as an image, PDF, or audio file. It is declared with the NDATA keyword plus a notation name, for example:
<!ENTITY logo SYSTEM "logo.png" NDATA png>When the parser meets such a declaration in the document's DTD, it invokes your handler so you can record where the resource lives instead of trying to load it as markup.
Syntax
xml_set_unparsed_entity_decl_handler(
XMLParser $parser,
callable $handler
): true| Parameter | Description |
|---|---|
$parser | The XML parser created with xml_parser_create(). |
$handler | A callable, or the string name of a function. Pass an empty string ("") to remove the current handler. |
Return value: always returns true.
PHP 8 note: since PHP 8.0 the parser is an
XMLParserobject rather than aresource, but the code you write is identical — keep treating the valuexml_parser_create()returns as an opaque handle.
The callback signature
Your handler is called with six arguments, in this order:
handler(
XMLParser $parser,
string $entityName, // e.g. "logo"
string $base, // base URI used to resolve the system id (often empty)
string $systemId, // e.g. "logo.png"
string $publicId, // public id, if any
string $notationName // e.g. "png" — declared with xml_set_notation_decl_handler()
): voidExample: capturing unparsed entity declarations
Create a SAX parser with xml_parser_create(), register the handler, then feed the XML to xml_parse():
<?php
function handleUnparsedEntity($parser, $name, $base, $systemId, $publicId, $notationName) {
echo "Unparsed entity '$name' -> $systemId (notation: $notationName)\n";
}
$xmlParser = xml_parser_create();
xml_set_unparsed_entity_decl_handler($xmlParser, "handleUnparsedEntity");
$xml = '<?xml version="1.0"?>
<!DOCTYPE catalog [
<!NOTATION png SYSTEM "image/png">
<!ENTITY logo SYSTEM "logo.png" NDATA png>
<!ENTITY manual SYSTEM "manual.pdf" NDATA pdf>
]>
<catalog/>';
xml_parse($xmlParser, $xml, true);
xml_parser_free($xmlParser);Expected output:
Unparsed entity 'logo' -> logo.png (notation: png)
Unparsed entity 'manual' -> manual.pdf (notation: pdf)The handler fires once per NDATA entity in the DTD, giving you the file path ($systemId) and notation. A real application would store these references — say, to download the assets later — rather than echo them.
Common gotchas
- The DTD must contain
NDATAdeclarations. A normal internal entity (<!ENTITY name "value">) is parsed text, so this handler never sees it. Only entities markedNDATA notationare "unparsed". - Register handlers before calling
xml_parse(). Like everyxml_set_*_handler()function, this one has no effect once parsing has started. - Free the parser with
xml_parser_free()when you are done to release resources. - Not in SimpleXML. If you are reading well-formed XML and don't need to react to DTD entity declarations, the simpler SimpleXML parser is usually the better choice.
Related functions
xml_parser_create()— create the SAX parser this handler attaches to.xml_set_notation_decl_handler()— handle the<!NOTATION ...>declarations referenced by unparsed entities.xml_set_external_entity_ref_handler()— handle parsed external entity references.xml_set_element_handler()— handle element start/end events.
Conclusion
xml_set_unparsed_entity_decl_handler() lets a SAX parser notify you about NDATA entities — references to external binary data — so you can capture their paths and notations without trying to parse them as XML. Register the handler before xml_parse(), expect the six-argument callback, and remember the function applies only to the procedural XML Parser extension, not to SimpleXML or DOM.