W3docs

xml_set_external_entity_ref_handler()

Функция xml_set_external_entity_ref_handler() регистрирует пользовательский обработчик внешних ссылок на сущности в SAX-парсере PHP.

Функция xml_set_external_entity_ref_handler() — встроенная функция PHP, которая регистрирует пользовательский обратный вызов для обработки внешних ссылок на сущности в устаревшем SAX (Expat) XML-парсере. Внешняя сущность — это ссылка внутри XML-документа, объявленная через <!ENTITY name SYSTEM "uri">, которая указывает на содержимое, хранящееся вне документа. Когда парсер встречает такую ссылку в процессе разбора, он вызывает ваш обратный вызов, чтобы вы могли решить, что с ней делать: проигнорировать, загрузить одобренные данные из базы данных или отклонить как часть проверки безопасности.

На этой странице рассматриваются синтаксис функции, параметры, которые PHP передаёт вашему обратному вызову, возвращаемое значение, полный рабочий пример, а также предостережения по безопасности и об устаревании, которые необходимо знать перед использованием.

Синтаксис

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

Параметры

ПараметрОписание
$parserРесурс XML-парсера, созданный с помощью xml_parser_create(). Обработчик привязывается к данному конкретному парсеру.
$handlerОбратный вызов, выполняемый при каждой внешней ссылке на сущность. Может быть именем функции (в виде строки) или — если использовался xml_set_object() — именем метода. Передача пустой строки отменяет регистрацию обработчика.

Возвращаемое значение

Возвращает true при успехе или false при ошибке (например, если $parser не является допустимым парсером).

Сигнатура обратного вызова

PHP вызывает ваш обработчик с пятью аргументами в следующем порядке:

handler(XMLParser $parser, string $open_entity_names, string $base, string $system_id, ?string $public_id): int
  • $open_entity_names — разделённый пробелами список сущностей, открытых в данный момент; используется для обнаружения рекурсии.
  • $base — базовый URI для разрешения $system_id (обычно пустая строка).
  • $system_id — системный идентификатор (URI из SYSTEM "...") внешней сущности.
  • $public_id — публичный идентификатор или null, если он не был объявлен.

Ваш обратный вызов должен возвращать ненулевое (истинное) значение, чтобы парсинг продолжился. Возврат 0, false или отсутствие возвращаемого значения прерывает разбор с ошибкой XML_ERROR_EXTERNAL_ENTITY_HANDLING.

Примеры использования

Рассмотрим практический пример использования xml_set_external_entity_ref_handler() в PHP.

Пример: установка функции-обработчика внешних ссылок на сущности

Предположим, у вас есть XML-документ, который ссылается на внешнюю сущность, и вы хотите проверить эту ссылку в процессе разбора. Вы создаёте парсер с помощью xml_parser_create(), регистрируете обработчик, разбираете данные с помощью xml_parse() и освобождаете парсер с помощью xml_parser_free():

Установка функции-обработчика внешних ссылок на сущности в 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);

Обработчик срабатывает один раз для ссылки &ext; и выводит:

External entity referenced: data.xml

Поскольку обратный вызов только выводит системный идентификатор и возвращает 1, парсеру даётся команда продолжить работу без фактической загрузки data.xml — что является именно тем безопасным поведением по умолчанию, которое вам нужно.

Почему обработчик может никогда не сработать

В большинстве современных сборок PHP загрузка внешних сущностей отключена на уровне libxml, поэтому парсер молча игнорирует ссылки на сущности, и ваш обратный вызов никогда не вызывается. Это намеренное ужесточение безопасности. Если вам необходимо включить её, управление осуществляется глобально с помощью libxml_disable_entity_loader() — однако для чего-либо кроме доверенных и контролируемых входных данных загрузку следует оставить отключённой.

⚠️ Предупреждение о безопасности: Обработка внешних сущностей — классический вектор для атак XML External Entity (XXE), которые могут раскрыть локальные файлы (file:///etc/passwd), инициировать запросы на стороне сервера или вызвать отказ в обслуживании. Никогда не разрешайте $system_id для загрузки произвольных URI или локальных путей из ненадёжных входных данных. Для разбора, чувствительного к безопасности, предпочтительнее использовать современные библиотеки, такие как DOMDocument или XMLReader, с отключённой загрузкой сущностей.

Примечание об устаревании: Начиная с PHP 8.4, передача некаллабельной строки в качестве обработчика является устаревшей — простое имя функции, которая существует, по-прежнему работает, но неразрешённая строка теперь вызывает уведомление об устаревании. Для прямой совместимости передавайте настоящий callable, например Closure или массив [$object, 'method']. Устаревшее расширение Expat SAX в целом находится в режиме обслуживания — для нового кода рекомендуется использовать XMLReader или DOMDocument.

Заключение

В этой статье мы рассмотрели функцию PHP xml_set_external_entity_ref_handler(): её синтаксис, пять аргументов, которые PHP передаёт вашему обратному вызову, почему обратный вызов должен возвращать ненулевое значение для продолжения разбора, и полный рабочий пример. Мы также указали на две вещи, которые вызывают затруднения: обработчик часто никогда не срабатывает, поскольку загрузка внешних сущностей по умолчанию отключена, а передача ненадёжных входных данных через него открывает возможность для XXE-атак. Используйте его только с доверенными данными, предпочитайте настоящий callable вместо строкового имени на PHP 8.4+, и для чего-либо чувствительного к безопасности обращайтесь к XMLReader или DOMDocument.

Для получения информации о связанных SAX-обработчиках смотрите xml_set_element_handler() и xml_set_object().

Практика

Практика
Какая функция PHP используется для установки обработчика внешних ссылок на сущности для XML-файлов?
Какая функция PHP используется для установки обработчика внешних ссылок на сущности для XML-файлов?
Was this page helpful?