libxml_set_external_entity_loader() 函数用于设置自定义的外部实体加载器,用于处理XML文档中的外部实体引用。这在增强XML处理的安全性和灵活性方面非常有用。
libxml_set_external_entity_loader(?callable $resolver = null): bool
| 参数 | 类型 | 描述 |
|---|---|---|
resolver |
callable|null | 回调函数,用于加载外部实体。传入null可以恢复默认加载器 |
成功时返回 true,失败时返回 false。
创建一个自定义的外部实体加载器,用于控制外部实体的访问:
<?php
// 自定义外部实体加载器
function customEntityLoader($public, $system, $context) {
// 只允许从特定域名加载外部实体
$allowedDomains = ['https://trusted-domain.com/', 'https://api.example.com/'];
foreach ($allowedDomains as $domain) {
if (strpos($system, $domain) === 0) {
return file_get_contents($system);
}
}
// 对于不允许的域,返回空字符串
return '';
}
// 设置自定义加载器
libxml_set_external_entity_loader('customEntityLoader');
// 禁用实体加载(安全选项)
libxml_disable_entity_loader(false);
// 解析XML
$xml = '<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY external SYSTEM "https://trusted-domain.com/data.xml">
]>
<root>
<content>&external;</content>
</root>';
$dom = new DOMDocument();
$dom->loadXML($xml);
echo $dom->saveXML();
// 恢复默认加载器
libxml_set_external_entity_loader(null);
?>
使用libxml_set_external_entity_loader()来防止XML外部实体(XXE)攻击:
<?php
// 安全的外部实体加载器 - 阻止所有外部实体
function secureEntityLoader($public, $system, $context) {
// 记录尝试访问的外部实体(用于监控)
error_log("Attempt to load external entity: " . $system);
// 抛出异常,阻止外部实体加载
throw new Exception("External entity loading is not allowed: " . $system);
// 或者返回空字符串/固定内容
// return '';
}
// 设置安全加载器
libxml_set_external_entity_loader('secureEntityLoader');
try {
// 尝试解析包含外部实体的XML
$xml = '<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>';
$dom = new DOMDocument();
$dom->loadXML($xml);
echo "XML parsed successfully (this should not happen)";
} catch (Exception $e) {
echo "Security error: " . $e->getMessage();
}
// 恢复默认加载器
libxml_set_external_entity_loader(null);
?>
从数据库加载预定义的外部实体内容:
<?php
// 假设这是数据库连接(示例用数组模拟)
$entityDatabase = [
'user_data' => '<user><name>John Doe</name><email>john@example.com</email></user>',
'app_config' => '<config><version>1.0</version><debug>false</debug></config>'
];
function databaseEntityLoader($public, $system, $context) {
global $entityDatabase;
// 从system标识符中提取实体名称
$entityName = basename($system, '.xml');
if (isset($entityDatabase[$entityName])) {
return $entityDatabase[$entityName];
}
// 如果没有找到,返回默认内容或空字符串
return "<error>Entity not found: $entityName</error>";
}
// 设置数据库加载器
libxml_set_external_entity_loader('databaseEntityLoader');
// 解析使用数据库实体的XML
$xml = '<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY user SYSTEM "user_data.xml">
<!ENTITY config SYSTEM "app_config.xml">
]>
<root>
&user;
&config;
</root>';
$dom = new DOMDocument();
$dom->loadXML($xml);
echo htmlspecialchars($dom->saveXML());
// 恢复默认加载器
libxml_set_external_entity_loader(null);
?>
libxml_disable_entity_loader(false)来启用实体加载| PHP版本 | 支持情况 |
|---|---|
| PHP 5.3+ | 支持 |
| PHP 7.0+ | 支持 |
| PHP 8.0+ | 支持 |