Signatur
Beschreibung
Mit xml_set_external_entity_ref_handler() wird ein Handler (Callback) für einen XML-Parser registriert, der immer dann aufgerufen wird, wenn der Parser auf eine externe Entity-Referenz stößt – also auf Referenzen der Form &entityname;, die in einer externen DTD oder über eine SYSTEM- oder PUBLIC-Deklaration definiert sind.
Der Handler erhält folgende Parameter: das Parser-Objekt, den Namen der Entity, die System-ID, die öffentliche ID (Public Identifier) und den Notationsnamen. Damit kann die Anwendung entscheiden, wie externe Entitäten aufgelöst werden sollen, z. B. ob deren Inhalt nachgeladen, ignoriert oder aus Sicherheitsgründen abgelehnt werden soll.
Diese Funktion ist besonders relevant, wenn XML-Dokumente mit einer DTD verarbeitet werden, die externe Entities deklariert. Ohne registrierten Handler ignoriert der Expat-basierte Parser solche Referenzen stillschweigend. In sicherheitssensiblen Anwendungen sollte ein Handler registriert werden, der externe Entities explizit ablehnt, um XXE-Angriffe (XML External Entity Injection) zu verhindern.
Die Funktion gibt true zurück, wenn der Handler erfolgreich registriert wurde, andernfalls false.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $parser Pflicht | XMLParser | Eine gültige XML-Parser-Ressource, die zuvor mit xml_parser_create() oder xml_parser_create_ns() erzeugt wurde. |
|
| $handler Pflicht | callable | Ein aufrufbares PHP-Callable (Funktionsname als String, anonyme Funktion oder Array mit Objekt und Methode). Die Callback-Signatur lautet: handler(XMLParser $parser, string $open_entity_names, string|false $base, string $system_id, string|false $public_id): bool. Gibt die Callback-Funktion false zurück, wird ein Fehler im Parser ausgelöst. |
Rückgabewert
true zurück, wenn der Handler erfolgreich gesetzt wurde, andernfalls false.Beispiele
Externe Entity-Referenzen protokollieren und ablehnen
<?php
$parser = xml_parser_create();
function externalEntityHandler(
XMLParser $parser,
string $openEntityNames,
string|false $base,
string $systemId,
string|false $publicId
): bool {
// Aus Sicherheitsgründen externe Entities ablehnen
echo "Externe Entity-Referenz abgelehnt: {$openEntityNames}" . PHP_EOL;
echo "System-ID: {$systemId}" . PHP_EOL;
// false zurückgeben, damit der Parser einen Fehler meldet
return false;
}
xml_set_external_entity_ref_handler($parser, 'externalEntityHandler');
$xml = '<?xml version="1.0"?>' .
'<!DOCTYPE foo [<!ENTITY ext SYSTEM "http://example.com/ext.xml">]>' .
'<root>&ext;</root>';
if (!xml_parse($parser, $xml, true)) {
echo 'XML-Fehler: ' . xml_error_string(xml_get_error_code($parser)) . PHP_EOL;
}
xml_parser_free($parser);
Externe Entity-Inhalte aus einer lokalen Datei laden
<?php
$parser = xml_parser_create();
$collectedData = '';
xml_set_character_data_handler($parser, function (XMLParser $p, string $data) use (&$collectedData) {
$collectedData .= $data;
});
xml_set_external_entity_ref_handler(
$parser,
function (
XMLParser $parser,
string $openEntityNames,
string|false $base,
string $systemId,
string|false $publicId
) use (&$collectedData): bool {
// Nur lokale Dateien erlauben – keine Netzwerkzugriffe
if (str_starts_with($systemId, 'file://') || !str_contains($systemId, '://')) {
$path = ltrim(str_replace('file://', '', $systemId), '/');
if (file_exists($path)) {
$subParser = xml_parser_create();
xml_set_character_data_handler($subParser, function (XMLParser $p, string $d) use (&$collectedData) {
$collectedData .= $d;
});
xml_parse($subParser, file_get_contents($path), true);
xml_parser_free($subParser);
return true;
}
}
// Externe Entities (HTTP etc.) ablehnen
return false;
}
);
$xml = '<?xml version="1.0"?>' .
'<!DOCTYPE doc [<!ENTITY local SYSTEM "local_data.xml">]>' .
'<doc>&local;</doc>';
xml_parse($parser, $xml, true);
xml_parser_free($parser);
echo 'Geladene Daten: ' . htmlspecialchars($collectedData);
// Wichtig · Fallstricke
Sicherheitshinweis (XXE – XML External Entity Injection): Externe Entities sind ein bekanntes Angriffsvektors. Ein Angreifer kann über manipulierte XML-Dokumente interne Dateien lesen (z. B. /etc/passwd) oder Server-seitige Anfragen (SSRF) auslösen, wenn externe Entities unreflektiert aufgelöst werden. Es wird empfohlen, im Handler generell false zurückzugeben oder nur explizit erlaubte, lokale Quellen zu akzeptieren.
Der PHP-eigene Expat-basierte XML-Parser lädt externe Entities nicht automatisch; ein nicht registrierter Handler ignoriert sie stillschweigend. Erst durch einen selbst registrierten Handler, der true zurückgibt und Inhalte nachlädt, entsteht ein potenzielles Risiko.
Seit PHP 8.0.0 ist der erste Parameter vom Typ XMLParser (Objekt) statt der früheren Ressource. Die Funktion ist Teil der prozeduralen XML-API; für objektorientierte Alternativen empfiehlt sich SimpleXML oder DOMDocument mit deaktivierter LIBXML_NOENT-Option.