Guía de referencia de la biblioteca PHP libxml
Guía de la extensión PHP libxml: captura errores de análisis, valida XML con SimpleXML o DOM y evita XXE en entradas no confiables.
Esta guía cubre la extensión PHP libxml: qué es, cómo los analizadores XML de PHP reportan errores a través de ella, y cómo analizar, validar y manipular XML de forma segura. La idea principal a tener en cuenta es que libxml es la capa compartida de reporte de errores y configuración que se encuentra bajo SimpleXML, DOM y XMLReader; una vez que la entiendas, cada extensión XML en PHP será más fácil de depurar.
¿Qué es PHP libxml?
libxml es la biblioteca C que PHP utiliza para casi todo su procesamiento XML. La extensión PHP libxml expone el manejo de errores y las opciones del analizador de esa biblioteca a tu código. Raramente la llamas directamente — en su lugar usas una extensión de nivel superior construida sobre ella:
- SimpleXML — la forma rápida y similar a un array para leer XML.
- DOM (
DOMDocument) — acceso completo de lectura/escritura al árbol del documento. XMLReader/XMLWriter— análisis en streaming, eficiente en memoria para archivos grandes.
Cuando cualquiera de estas encuentra XML malformado, reporta el problema a través de libxml. Las funciones libxml_* permiten capturar, inspeccionar y limpiar esos errores.
Instalación de PHP libxml
La extensión libxml está incluida y habilitada por defecto — no hay nada que instalar. Puedes confirmar que está activa en tiempo de ejecución:
<?php
var_dump(extension_loaded('libxml')); // bool(true)
echo LIBXML_DOTTED_VERSION; // e.g. "2.9.14" — the linked libxml2 version
?>Si una compilación personalizada reporta false, recompila PHP con --with-libxml (versiones antiguas de PHP usaban --enable-libxml).
Manejo de errores de libxml
Esta es la parte más importante de la extensión. Por defecto, un documento malformado emite advertencias de PHP, lo cual es difícil de manejar en producción. En su lugar, cambia al modo de error interno: libxml entonces recopila los errores en un buffer que tú mismo lees.
<?php
// Stop warnings; buffer errors instead.
libxml_use_internal_errors(true);
$broken = '<root><item>unclosed</root>';
$xml = simplexml_load_string($broken);
if ($xml === false) {
foreach (libxml_get_errors() as $error) {
// Each $error is a LibXMLError object.
printf(
"[%s] line %d: %s",
$error->level === LIBXML_ERR_FATAL ? 'fatal' : 'warning',
$error->line,
trim($error->message)
);
echo PHP_EOL;
}
libxml_clear_errors(); // Empty the buffer so it doesn't leak into later parses.
}
?>Un LibXMLError expone level (LIBXML_ERR_WARNING, LIBXML_ERR_ERROR, LIBXML_ERR_FATAL), code, message, line, column y file. Funciones relacionadas:
libxml_use_internal_errors()— activar/desactivar el buffering.libxml_get_errors()— devuelve todos los errores almacenados como un array.libxml_get_last_error()— devuelve solo el error más reciente.libxml_clear_errors()— vacía el buffer.
Análisis de documentos XML
El uso más común de XML en PHP es leer un documento. simplexml_load_string() (y su equivalente para archivos simplexml_load_file()) devuelven false en caso de fallo, por lo que siempre combínalos con el modo de error interno:
<?php
libxml_use_internal_errors(true);
$source = '<catalog><book id="1">PHP Basics</book></catalog>';
$xml = simplexml_load_string($source);
if ($xml === false) {
echo "Failed to parse XML." . PHP_EOL;
foreach (libxml_get_errors() as $error) {
echo trim($error->message) . PHP_EOL;
}
libxml_clear_errors();
} else {
echo "Loaded: " . $xml->book . PHP_EOL; // Loaded: PHP Basics
echo "id = " . $xml->book['id'] . PHP_EOL; // id = 1
}
?>Opciones del analizador (constantes de libxml)
La mayoría de las funciones XML aceptan una máscara de bits $options con constantes LIBXML_*. Combínalas con el operador OR bit a bit (|):
<?php
$xml = simplexml_load_string(
'<a> <b>text</b> </a>',
'SimpleXMLElement',
LIBXML_NOCDATA | LIBXML_NOBLANKS // drop CDATA wrappers + ignore whitespace-only nodes
);
echo $xml->b; // text
?>Opciones de uso frecuente:
| Constante | Efecto |
|---|---|
LIBXML_NOBLANKS | Elimina nodos en blanco (solo espacios en blanco). |
LIBXML_NOCDATA | Fusiona secciones CDATA como texto plano. |
LIBXML_NOERROR / LIBXML_NOWARNING | Suprime errores / advertencias. |
LIBXML_COMPACT | Optimización de nodos pequeños para documentos grandes. |
LIBXML_NOENT | Sustituye entidades — peligroso con entradas no confiables (ver más abajo). |
Seguridad: XML no confiable y XXE
Los ataques de Entidad Externa XML (XXE) permiten que un documento malicioso lea archivos locales o desencadene solicitudes de red. Nunca habilites la carga de entidades en entradas que no controles. Los valores predeterminados seguros en PHP moderno (7.0+) ya deshabilitan la carga de entidades externas, por lo que la regla es simple:
- No pases
LIBXML_NOENTniLIBXML_DTDLOADal analizar XML no confiable. - En PHP < 8.0 también puedes llamar a
libxml_disable_entity_loader(true)como una protección adicional. Consultalibxml_disable_entity_loader()para más detalles (la función está obsoleta en 8.0+ porque la carga está desactivada por defecto).
Validación de documentos XML
libxml puede validar un documento contra un DTD o un esquema XSD. DOMDocument::schemaValidate() es la forma más directa, y los errores de validación fluyen a través del mismo buffer:
<?php
libxml_use_internal_errors(true);
$doc = new DOMDocument();
if (!$doc->load('example.xml')) {
echo "Could not load document." . PHP_EOL;
exit;
}
if ($doc->schemaValidate('example.xsd')) {
echo "The XML document is valid." . PHP_EOL;
} else {
echo "Validation failed:" . PHP_EOL;
foreach (libxml_get_errors() as $error) {
echo " line {$error->line}: " . trim($error->message) . PHP_EOL;
}
libxml_clear_errors();
}
?>Para archivos muy grandes, prefiere el streaming XMLReader, que valida mientras lee sin cargar todo el documento en memoria:
<?php
$reader = new XMLReader();
$reader->open('example.xml');
$reader->setSchema('example.xsd'); // attach the XSD before reading
$valid = true;
while ($reader->read()) {
if (!$reader->isValid()) {
$valid = false;
break;
}
}
$reader->close();
echo $valid ? "Document is valid." : "Document is not valid.";
?>Manipulación de documentos XML
Para modificar un documento generalmente se usa DOM. El ejemplo siguiente construye un documento en memoria (por lo que se ejecuta sin ningún archivo externo), agrega un nodo e imprime el resultado:
<?php
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->formatOutput = true; // pretty-print the output
// Build a root, then add a child element with text content.
$root = $doc->createElement('catalog');
$doc->appendChild($root);
$book = $doc->createElement('book', 'Learning PHP');
$book->setAttribute('id', '42');
$root->appendChild($book);
echo $doc->saveXML();
// <?xml version="1.0" encoding="UTF-8"?>
// <catalog>
// <book id="42">Learning PHP</book>
// </catalog>
?>Al editar un archivo desde disco, cárgalo, localiza el nodo objetivo con getElementsByTagName(), agrega al nodo (no al documento, que solo puede tener un elemento raíz) y luego guárdalo con save().
¿Cuándo lo usaría?
- Leer datos de configuración o feeds (RSS/Atom, respuestas SOAP, sitemaps) — analiza con SimpleXML, protege con errores internos.
- Validar cargas — rechaza documentos que fallen
schemaValidate()antes de confiar en ellos. - Generar XML para una API o exportación — constrúyelo con DOM para que los atributos y la codificación se manejen correctamente.
- Depurar fallos de "XML inválido" — lee
libxml_get_errors()para ver la línea y columna exactas.
Conclusión
La extensión libxml es la base del stack XML de PHP. El patrón que da resultados en todos los casos es: llama a libxml_use_internal_errors(true), analiza o valida, luego inspecciona libxml_get_errors() y libxml_clear_errors(). A partir de ahí, elige la herramienta adecuada — SimpleXML para lecturas rápidas, DOM para edición, XMLReader para archivos grandes — y pasa opciones LIBXML_* para controlar el comportamiento del analizador. Mantén la carga de entidades desactivada para entradas no confiables y tu manejo de XML será robusto y seguro.