W3docs

xml_set_external_entity_ref_handler()

The xml_set_external_entity_ref_handler() function is a PHP built-in function that sets a user-defined function as the handler for external entity references in

The xml_set_external_entity_ref_handler() function is a PHP built-in function that registers a user-defined callback to handle external entity references in a legacy SAX (Expat) XML parser. An external entity is a reference inside an XML document — declared with <!ENTITY name SYSTEM "uri"> — that points to content stored outside the document. When the parser meets such a reference during parsing, it invokes your callback so you can decide what to do with it: ignore it, load approved data from a database, or reject it as part of security validation.

This page covers the function's syntax, the parameters PHP passes to your callback, its return value, a complete runnable example, and the security and deprecation caveats you need to know before using it.

Syntax

xml_set_external_entity_ref_handler(XMLParser $parser, callable $handler): bool

Parameters

ParameterDescription
$parserThe XML parser resource created with xml_parser_create(). The handler is attached to this specific parser.
$handlerThe callback to run on each external entity reference. It can be the name of a function (as a string), or — when xml_set_object() was used — a method name. Passing an empty string unsets the handler.

Return value

Returns true on success, or false on failure (for example, if $parser is not a valid parser).

The callback signature

PHP calls your handler with five arguments, in this order:

handler(XMLParser $parser, string $open_entity_names, string $base, string $system_id, ?string $public_id): int
  • $open_entity_names — a space-separated list of the entities that are currently open, used to detect recursion.
  • $base — the base URI for resolving $system_id (usually an empty string).
  • $system_id — the system identifier (the SYSTEM "..." URI) of the external entity.
  • $public_id — the public identifier, or null if none was declared.

Your callback must return a non-zero (truthy) value to keep the parse going. Returning 0, false, or nothing aborts the parse with an XML_ERROR_EXTERNAL_ENTITY_HANDLING error.

Usage Examples

Let's take a look at a practical example of using xml_set_external_entity_ref_handler() in PHP.

Example: Setting an External Entity Reference Handler Function

Suppose you have an XML document that references an external entity and you want to inspect that reference as the document is parsed. You create a parser with xml_parser_create(), register the handler, parse the data with xml_parse(), and free the parser with xml_parser_free():

Setting an External Entity Reference Handler Function in PHP

function handle_external_entity_ref($parser, $open_entity_names, $base, $system_id, $public_id) {
    // Inspect — but do NOT blindly load — the external entity.
    echo "External entity referenced: {$system_id}\n";

    // Return a non-zero value so parsing continues.
    return 1;
}

$xml_parser = xml_parser_create();
xml_set_external_entity_ref_handler($xml_parser, "handle_external_entity_ref");

$xml_data = '<?xml version="1.0"?>
<!DOCTYPE root [
  <!ENTITY ext SYSTEM "data.xml">
]>
<root>&ext;</root>';

xml_parse($xml_parser, $xml_data, true);
xml_parser_free($xml_parser);

The handler fires once for the &ext; reference and prints:

External entity referenced: data.xml

Because the callback only echoes the system identifier and returns 1, the parser is told to continue without actually fetching data.xml — which is exactly the safe default you want.

Why the handler may never fire

In most modern PHP builds, external entity loading is disabled at the libxml level, so the parser silently ignores entity references and your callback is never called. This is intentional hardening. If you must opt in, you control it globally with libxml_disable_entity_loader() — but for anything but trusted, controlled input you should leave loading disabled.

⚠️ Security Warning: Handling external entities is a classic vector for XML External Entity (XXE) attacks, which can leak local files (file:///etc/passwd), trigger server-side requests, or cause denial of service. Never resolve $system_id to fetch arbitrary URIs or local paths from untrusted input. For security-sensitive parsing, prefer modern libraries such as DOMDocument or XMLReader with entity loading turned off.

Deprecation note: As of PHP 8.4, passing a non-callable string as the handler is deprecated — a plain function name that actually exists still works, but an unresolved string now raises a deprecation notice. For forward-compatible code, pass a real callable such as a Closure or a [$object, 'method'] array. The legacy Expat SAX extension as a whole is in maintenance mode — new code should favor XMLReader or DOMDocument.

Conclusion

In this article, we've covered PHP's xml_set_external_entity_ref_handler() function: its syntax, the five arguments PHP passes to your callback, why the callback must return a non-zero value to keep parsing alive, and a complete runnable example. We've also flagged the two things that trip people up — the handler often never fires because external entity loading is disabled by default, and routing untrusted input through it opens the door to XXE attacks. Use it only with trusted input, prefer a real callable over a string name on PHP 8.4+, and reach for XMLReader or DOMDocument for anything security-sensitive.

For related SAX handlers, see xml_set_element_handler() and xml_set_object().

Practice

Practice
What function in PHP is used to create an external entity reference for XML files?
What function in PHP is used to create an external entity reference for XML files?
Was this page helpful?