libxml_disable_entity_loader()
Today we will discuss the libxml_disable_entity_loader() function in PHP. This function is used to disable the loading of external entities in XML documents.
The PHP libxml_disable_entity_loader() function was used to turn external-entity loading on or off for every XML document parsed by the libxml extension. This page explains what the function did, the XML External Entity (XXE) attack it protected against, why it was removed, and exactly how to write secure XML-parsing code in modern PHP.
Important: libxml_disable_entity_loader() was deprecated in PHP 8.0 and removed in PHP 8.1. If you are on PHP 8.1 or newer, calling it raises a fatal error. Use the secure alternatives below instead.
What libxml_disable_entity_loader() Did
libxml_disable_entity_loader() was a built-in PHP utility that toggled a global flag inside libxml — the C library that powers PHP's DOMDocument and SimpleXML. When the flag was set, libxml refused to resolve external entities: references inside an XML document that point at an outside resource such as a local file (file:///etc/passwd) or a remote URL.
Blocking that resolution was the standard way to defend against XML External Entity (XXE) attacks. In an XXE attack, the attacker submits an XML payload whose DOCTYPE declares an entity pointing at a sensitive resource:
<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<data>&xxe;</data>If the parser resolves &xxe;, the contents of /etc/passwd end up in the parsed document — which the application might then echo back, log, or store. The same trick enables server-side request forgery (SSRF, by pointing the entity at an internal URL) and denial of service (the "billion laughs" entity-expansion bomb).
Syntax
libxml_disable_entity_loader(bool $disable = true): boolParameters
| Parameter | Type | Description |
|---|---|---|
$disable | bool | true disables external-entity loading; false re-enables it. Defaults to true. |
Return value
Returns the previous value of the flag as a boolean, so you could restore the prior state after a single parse.
Legacy Usage
In PHP 7.x and earlier, securing a parse looked like this. The call is wrapped in function_exists() so the same code keeps working on PHP 8.1+, where the function no longer exists:
<?php
// Disable external entities (deprecated in PHP 8.0, removed in 8.1).
if (function_exists('libxml_disable_entity_loader')) {
libxml_disable_entity_loader(true);
}
// Load an XML file into a DOMDocument object.
$doc = new DOMDocument();
if (!$doc->load('example.xml')) {
die('Failed to load XML file.');
}
?>A common, safer pattern was to capture the previous value and restore it, so disabling entities did not leak into unrelated parsing elsewhere in the request:
<?php
$previous = libxml_disable_entity_loader(true);
$doc = new DOMDocument();
$doc->loadXML($untrustedXml);
// Restore the global flag for the rest of the request.
libxml_disable_entity_loader($previous);
?>Secure Alternatives in Modern PHP
Two things changed in modern PHP that made the function unnecessary:
- libxml 2.9+ disables external-entity loading by default. Since that version (shipped with PHP for years), DTD external entities are not resolved unless you explicitly ask for them. This is why the function became redundant and was removed.
LIBXML_NONETgives per-call control. Instead of flipping a global flag, you pass a flag to the specific load call, which blocks network access during parsing:
<?php
$doc = new DOMDocument();
// Parse without ever touching the network — no SSRF, no remote entities.
$doc->load('example.xml', LIBXML_NONET);
?>If you must support DTDs but still want hardening, avoid LIBXML_DTDLOAD / LIBXML_NOENT on untrusted input, since those flags re-enable the very behavior XXE relies on. The safest default is simply to not pass them:
<?php
$doc = new DOMDocument();
// Default flags (0): no entity substitution, no DTD loading from untrusted XML.
$doc->loadXML($untrustedXml);
// SimpleXML follows the same secure default.
$xml = simplexml_load_string($untrustedXml);
?>To inspect any parse problems instead of emitting raw warnings, combine the load with libxml_use_internal_errors() and read them via libxml_get_errors().
When Would I Use This?
You will only ever encounter libxml_disable_entity_loader() while reading or maintaining legacy PHP 7 code. For any code you write today:
- On PHP 8.1+, do nothing special for entities — the secure default already applies. Add
LIBXML_NONETwhen you also want to block network access. - Migrating old code? Replace
libxml_disable_entity_loader(true)with theLIBXML_NONETflag on each load, or wrap the call infunction_exists()so it no-ops on new runtimes.
Conclusion
libxml_disable_entity_loader() was once the go-to defense against XXE attacks, but it relied on a fragile global flag and has been removed since PHP 8.1. Modern PHP is secure by default thanks to libxml 2.9+, and LIBXML_NONET gives you explicit, per-parse control. For more on PHP's XML stack, see the libxml extension overview and working with the XML DOM.