Guida di riferimento alla libreria PHP libxml
Guida all'estensione PHP libxml: gestione degli errori, parsing e validazione XML con SimpleXML o DOM, prevenzione degli attacchi XXE.
Questa guida copre l'estensione PHP libxml: cos'è, come i parser XML di PHP segnalano gli errori attraverso di essa e come effettuare il parsing, la validazione e la manipolazione di XML in modo sicuro. Il concetto fondamentale da assimilare è che libxml è il livello condiviso di segnalazione degli errori e configurazione sottostante a SimpleXML, DOM e XMLReader — una volta compreso, ogni estensione XML in PHP diventa più facile da gestire.
Cos'è PHP libxml?
libxml è la libreria C che PHP utilizza per quasi tutta la sua elaborazione XML. L'estensione PHP libxml espone la gestione degli errori e le opzioni del parser di quella libreria al tuo codice. Raramente la chiami direttamente — invece utilizzi un'estensione di livello superiore costruita su di essa:
- SimpleXML — il modo rapido, simile agli array, per leggere XML.
- DOM (
DOMDocument) — accesso completo in lettura/scrittura all'albero del documento. XMLReader/XMLWriter— parsing in streaming, efficiente in termini di memoria, per file di grandi dimensioni.
Quando uno di questi incontra XML malformato, segnala il problema attraverso libxml. Le funzioni libxml_* consentono di catturare, ispezionare e cancellare quegli errori.
Installare PHP libxml
L'estensione libxml è inclusa e abilitata per impostazione predefinita — non c'è nulla da installare. Puoi verificare che sia attiva in fase di esecuzione:
<?php
var_dump(extension_loaded('libxml')); // bool(true)
echo LIBXML_DOTTED_VERSION; // e.g. "2.9.14" — the linked libxml2 version
?>Se una build personalizzata restituisce false, ricompila PHP con --with-libxml (le versioni precedenti di PHP usavano --enable-libxml).
Gestire gli errori libxml
Questa è la parte più importante dell'estensione. Per impostazione predefinita, un documento malformato genera avvisi PHP, il che è scomodo da gestire in produzione. Invece, passa alla modalità errore interno: libxml raccoglie quindi gli errori in un buffer che puoi leggere tu stesso.
<?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 espone level (LIBXML_ERR_WARNING, LIBXML_ERR_ERROR, LIBXML_ERR_FATAL), code, message, line, column e file. Funzioni correlate:
libxml_use_internal_errors()— attiva/disattiva il buffering.libxml_get_errors()— restituisce tutti gli errori nel buffer come array.libxml_get_last_error()— restituisce solo l'errore più recente.libxml_clear_errors()— svuota il buffer.
Parsing di documenti XML
L'uso più comune di XML in PHP è la lettura di un documento. simplexml_load_string() (e la sua variante per file simplexml_load_file()) restituiscono false in caso di errore, quindi abbinale sempre alla modalità errore 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
}
?>Opzioni del parser (costanti libxml)
La maggior parte delle funzioni XML accetta una maschera di bit $options composta da costanti LIBXML_*. Combinale con l'operatore 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
?>Opzioni utilizzate frequentemente:
| Costante | Effetto |
|---|---|
LIBXML_NOBLANKS | Rimuove i nodi vuoti (solo spazi bianchi). |
LIBXML_NOCDATA | Unisce le sezioni CDATA come testo normale. |
LIBXML_NOERROR / LIBXML_NOWARNING | Sopprime errori / avvisi. |
LIBXML_COMPACT | Ottimizzazione per nodi piccoli in documenti di grandi dimensioni. |
LIBXML_NOENT | Sostituisce le entità — pericoloso con input non attendibile (vedi sotto). |
Sicurezza: XML non attendibile e XXE
Gli attacchi XML eXternal Entity (XXE) consentono a un documento malevolo di leggere file locali o innescare richieste di rete. Non abilitare mai il caricamento di entità su input che non controlli. Le impostazioni predefinite sicure in PHP moderno (7.0+) disabilitano già il caricamento di entità esterne, quindi la regola è semplice:
- Non passare
LIBXML_NOENToLIBXML_DTDLOADdurante il parsing di XML non attendibile. - Su PHP < 8.0 puoi chiamare anche
libxml_disable_entity_loader(true)come protezione aggiuntiva. Consultalibxml_disable_entity_loader()per i dettagli (la funzione è deprecata in 8.0+ perché il caricamento è disabilitato per impostazione predefinita).
Validare documenti XML
libxml può validare un documento rispetto a una DTD o a uno schema XSD. DOMDocument::schemaValidate() è il metodo più diretto, e gli errori di validazione fluiscono attraverso lo stesso 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();
}
?>Per file molto grandi, preferisci XMLReader in streaming, che valida durante la lettura senza caricare l'intero documento in 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.";
?>Manipolare documenti XML
Per modificare un documento si utilizza generalmente DOM. L'esempio seguente costruisce un documento in memoria (quindi funziona senza file esterni), aggiunge un nodo e stampa il risultato:
<?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>
?>Quando si modifica un file dal disco, caricalo, individua il nodo target con getElementsByTagName(), aggiungilo a quel nodo (non al documento, che può contenere un solo elemento radice), quindi salvalo con save().
Quando usarlo?
- Lettura di dati di configurazione o feed (RSS/Atom, risposte SOAP, sitemap) — effettua il parsing con SimpleXML, proteggi con la modalità errore interno.
- Validazione di upload — rifiuta i documenti che non superano
schemaValidate()prima di considerarli attendibili. - Generazione di XML per un'API o un'esportazione — costruiscilo con DOM in modo che attributi e codifica siano gestiti correttamente.
- Debug di errori "XML non valido" — leggi
libxml_get_errors()per vedere la riga e la colonna esatte.
Conclusione
L'estensione libxml è il fondamento dello stack XML di PHP. Il pattern che si rivela utile ovunque è: chiama libxml_use_internal_errors(true), effettua il parsing o la validazione, quindi ispeziona libxml_get_errors() e libxml_clear_errors(). Da lì, scegli lo strumento giusto — SimpleXML per letture rapide, DOM per la modifica, XMLReader per file di grandi dimensioni — e passa le opzioni LIBXML_* per controllare il comportamento del parser. Mantieni disabilitato il caricamento delle entità per input non attendibile e la gestione di XML sarà robusta e sicura.