Start · Sprachen · PHP · Referenz · xml_set_external_entity_ref_handler

xml_set_external_entity_ref_handler

Funktion

Registriert eine Callback-Funktion, die aufgerufen wird, wenn der XML-Parser auf eine externe Entity-Referenz trifft.

seit PHP 4.0.0 Kategorie: xml

Signatur

xml_set_external_entity_ref_handler(XMLParser $parser, callable $handler): bool

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

Typ
bool
Beschreibung
Gibt 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-Referenz abgelehnt: ext System-ID: http://example.com/ext.xml XML-Fehler: undefined entity

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);
Geladene Daten: (Inhalt von local_data.xml)

// 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.