xml_set_external_entity_ref_handler()
La función xml_set_external_entity_ref_handler() de PHP registra una función de usuario para manejar referencias a entidades externas en XML.
La función xml_set_external_entity_ref_handler() es una función integrada de PHP que registra una devolución de llamada definida por el usuario para manejar referencias a entidades externas en un analizador XML SAX (Expat) heredado. Una entidad externa es una referencia dentro de un documento XML — declarada con <!ENTITY name SYSTEM "uri"> — que apunta a contenido almacenado fuera del documento. Cuando el analizador encuentra dicha referencia durante el análisis, invoca tu devolución de llamada para que puedas decidir qué hacer con ella: ignorarla, cargar datos aprobados desde una base de datos o rechazarla como parte de la validación de seguridad.
Esta página cubre la sintaxis de la función, los parámetros que PHP pasa a tu devolución de llamada, su valor de retorno, un ejemplo completo ejecutable y las advertencias de seguridad y deprecación que debes conocer antes de usarla.
Sintaxis
xml_set_external_entity_ref_handler(XMLParser $parser, callable $handler): boolParámetros
| Parámetro | Descripción |
|---|---|
$parser | El recurso del analizador XML creado con xml_parser_create(). El manejador se adjunta a este analizador específico. |
$handler | La devolución de llamada que se ejecuta en cada referencia a una entidad externa. Puede ser el nombre de una función (como string), o — cuando se usó xml_set_object() — el nombre de un método. Pasar un string vacío elimina el manejador. |
Valor de retorno
Devuelve true en caso de éxito, o false en caso de fallo (por ejemplo, si $parser no es un analizador válido).
La firma de la devolución de llamada
PHP llama a tu manejador con cinco argumentos, en este orden:
handler(XMLParser $parser, string $open_entity_names, string $base, string $system_id, ?string $public_id): int$open_entity_names— una lista separada por espacios de las entidades que están actualmente abiertas, utilizada para detectar recursión.$base— el URI base para resolver$system_id(generalmente un string vacío).$system_id— el identificador de sistema (el URISYSTEM "...") de la entidad externa.$public_id— el identificador público, onullsi no se declaró ninguno.
Tu devolución de llamada debe devolver un valor distinto de cero (verdadero) para que el análisis continúe. Devolver 0, false o nada aborta el análisis con un error XML_ERROR_EXTERNAL_ENTITY_HANDLING.
Ejemplos de uso
Veamos un ejemplo práctico del uso de xml_set_external_entity_ref_handler() en PHP.
Ejemplo: Establecer una función manejadora de referencias a entidades externas
Supón que tienes un documento XML que referencia una entidad externa y quieres inspeccionar esa referencia mientras se analiza el documento. Creas un analizador con xml_parser_create(), registras el manejador, analizas los datos con xml_parse() y liberas el analizador con xml_parser_free():
Establecer una función manejadora de referencias a entidades externas en 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);El manejador se activa una vez para la referencia &ext; e imprime:
External entity referenced: data.xmlDado que la devolución de llamada solo muestra el identificador de sistema y devuelve 1, se le indica al analizador que continúe sin obtener realmente data.xml — que es exactamente el comportamiento seguro por defecto que se desea.
Por qué el manejador puede que nunca se active
En la mayoría de las compilaciones modernas de PHP, la carga de entidades externas está deshabilitada a nivel de libxml, por lo que el analizador ignora silenciosamente las referencias a entidades y tu devolución de llamada nunca se llama. Esto es un endurecimiento intencional. Si debes habilitarla, puedes controlarla globalmente con libxml_disable_entity_loader() — pero para cualquier cosa que no sea entrada de confianza y controlada, debes dejar la carga deshabilitada.
⚠️ Advertencia de seguridad: Manejar entidades externas es un vector clásico para ataques de XML External Entity (XXE), que pueden filtrar archivos locales (
file:///etc/passwd), desencadenar solicitudes del lado del servidor o causar denegación de servicio. Nunca resuelvas$system_idpara obtener URIs arbitrarios o rutas locales de entradas no confiables. Para análisis sensibles a la seguridad, prefiere bibliotecas modernas comoDOMDocumentoXMLReadercon la carga de entidades desactivada.
Nota de deprecación: A partir de PHP 8.4, pasar un string no ejecutable como manejador está deprecado — un nombre de función simple que realmente existe todavía funciona, pero un string no resuelto ahora genera un aviso de deprecación. Para código compatible hacia adelante, pasa un callable real como un
Closureo un array[$object, 'method']. La extensión SAX Expat heredada en su conjunto está en modo de mantenimiento — el nuevo código debería preferirXMLReaderoDOMDocument.
Conclusión
En este artículo, hemos cubierto la función xml_set_external_entity_ref_handler() de PHP: su sintaxis, los cinco argumentos que PHP pasa a tu devolución de llamada, por qué la devolución de llamada debe devolver un valor distinto de cero para mantener el análisis activo, y un ejemplo completo ejecutable. También hemos señalado las dos cosas que confunden a la gente — el manejador a menudo nunca se activa porque la carga de entidades externas está deshabilitada por defecto, y enrutar entradas no confiables a través de él abre la puerta a ataques XXE. Úsalo solo con entradas de confianza, prefiere un callable real sobre un nombre de string en PHP 8.4+, y recurre a XMLReader o DOMDocument para cualquier cosa sensible a la seguridad.
Para manejadores SAX relacionados, consulta xml_set_element_handler() y xml_set_object().