libxml_get_errors() 函数用于获取 libxml 错误缓冲区中的所有错误信息。当使用 libxml 库处理 XML 或 HTML 文档时(如通过 DOMDocument、SimpleXML、XMLReader),解析过程中产生的错误会存储在错误缓冲区中。此函数可以获取这些错误的详细信息。
libxml_use_internal_errors(true) 来启用内部错误处理模式,否则 libxml 会直接输出错误或触发 PHP 错误。
libxml_get_errors ( ) : array
该函数没有参数。
函数返回一个包含 LibXMLError 对象的数组。每个 LibXMLError 对象包含以下属性:
| 属性 | 类型 | 说明 |
|---|---|---|
level |
int | 错误级别(LIBXML_ERR_WARNING、LIBXML_ERR_ERROR、LIBXML_ERR_FATAL) |
code |
int | 错误代码 |
column |
int | 发生错误的列号(如果可用) |
message |
string | 错误消息文本 |
file |
string | 文件名(如果解析的是文件) |
line |
int | 发生错误的行号 |
LIBXML_ERR_WARNING (1) - 警告,解析可能有问题但不致命LIBXML_ERR_ERROR (2) - 错误,文档不符合规范LIBXML_ERR_FATAL (3) - 致命错误,文档无法解析下面的示例演示如何获取XML解析过程中的错误信息。
<?php
// 启用内部错误处理
libxml_use_internal_errors(true);
// 创建一个格式错误的XML
$malformed_xml = '<root>
<item>第一个项目</item>
<item>第二个项目<item> <!-- 缺少结束标签 -->
<item attribute="value">第三个项目</item>
</root>';
echo "<h4>解析格式错误的XML:</h4>";
echo "<pre>" . htmlspecialchars($malformed_xml) . "</pre>";
// 尝试解析XML
$doc = new DOMDocument();
$result = $doc->loadXML($malformed_xml);
if (!$result) {
echo "<div class='alert alert-danger'>XML解析失败!</div>";
// 获取所有错误
$errors = libxml_get_errors();
echo "<h5>发现 " . count($errors) . " 个错误:</h5>";
// 显示错误详情
foreach ($errors as $index => $error) {
echo "<div class='card mb-3" . ($error->level === LIBXML_ERR_FATAL ? ' border-danger' : '') . "'>";
echo "<div class='card-header" . ($error->level === LIBXML_ERR_FATAL ? ' bg-danger text-white' : ' bg-warning') . "'>";
// 错误级别
$level = '';
switch ($error->level) {
case LIBXML_ERR_WARNING: $level = '警告'; break;
case LIBXML_ERR_ERROR: $level = '错误'; break;
case LIBXML_ERR_FATAL: $level = '致命错误'; break;
}
echo "错误 #" . ($index + 1) . " - $level (代码: {$error->code})";
echo "</div>";
echo "<div class='card-body'>";
echo "<p class='card-text'><strong>消息:</strong> " . htmlspecialchars(trim($error->message)) . "</p>";
echo "<p class='card-text'><strong>位置:</strong> 行 {$error->line}, 列 " . ($error->column ?: '未知') . "</p>";
echo "</div></div>";
}
// 清除错误缓冲区(可选)
libxml_clear_errors();
} else {
echo "<div class='alert alert-success'>XML解析成功!</div>";
}
?>
下面的示例演示如何对错误进行分类、统计并生成格式化的报告。
<?php
/**
* 获取并格式化libxml错误
*/
function getFormattedXmlErrors($xml_string) {
// 启用内部错误处理
libxml_use_internal_errors(true);
// 清除之前的错误
libxml_clear_errors();
// 尝试解析XML
$doc = new DOMDocument();
$result = $doc->loadXML($xml_string);
// 获取错误
$errors = libxml_get_errors();
// 分类统计
$stats = [
'total' => 0,
'warnings' => 0,
'errors' => 0,
'fatal' => 0,
'by_code' => []
];
// 格式化错误信息
$formatted_errors = [];
foreach ($errors as $error) {
$stats['total']++;
// 按级别统计
switch ($error->level) {
case LIBXML_ERR_WARNING: $stats['warnings']++; break;
case LIBXML_ERR_ERROR: $stats['errors']++; break;
case LIBXML_ERR_FATAL: $stats['fatal']++; break;
}
// 按错误代码统计
$code = $error->code;
if (!isset($stats['by_code'][$code])) {
$stats['by_code'][$code] = 0;
}
$stats['by_code'][$code]++;
// 格式化错误信息
$level_name = '';
switch ($error->level) {
case LIBXML_ERR_WARNING: $level_name = '警告'; break;
case LIBXML_ERR_ERROR: $level_name = '错误'; break;
case LIBXML_ERR_FATAL: $level_name = '致命错误'; break;
}
$formatted_errors[] = [
'level' => $level_name,
'code' => $code,
'message' => trim($error->message),
'line' => $error->line,
'column' => $error->column,
'severity' => $error->level
];
}
return [
'success' => $result,
'stats' => $stats,
'errors' => $formatted_errors,
'document' => $result ? $doc : null
];
}
// 测试XML
$test_xml = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<root xmlns="http://www.w3.org/1999/xhtml">
<item>项目1</item>
<item>项目2<!-- 未闭合的注释 -->
<item invalid-attr="值">项目3</item>
<unknown-tag>未知标签</unknown-tag>
<item>特殊字符: & < ></item>
</root>';
echo "<h4>XML错误分析和统计:</h4>";
$result = getFormattedXmlErrors($test_xml);
// 显示统计信息
echo "<div class='row mb-4'>";
echo "<div class='col-md-3'>";
echo "<div class='card text-white bg-primary'>";
echo "<div class='card-body text-center'>";
echo "<h5 class='card-title'>总错误数</h5>";
echo "<p class='card-text display-6'>" . $result['stats']['total'] . "</p>";
echo "</div></div></div>";
echo "<div class='col-md-3'>";
echo "<div class='card text-white bg-warning'>";
echo "<div class='card-body text-center'>";
echo "<h5 class='card-title'>警告</h5>";
echo "<p class='card-text display-6'>" . $result['stats']['warnings'] . "</p>";
echo "</div></div></div>";
echo "<div class='col-md-3'>";
echo "<div class='card text-white bg-danger'>";
echo "<div class='card-body text-center'>";
echo "<h5 class='card-title'>错误</h5>";
echo "<p class='card-text display-6'>" . $result['stats']['errors'] . "</p>";
echo "</div></div></div>";
echo "<div class='col-md-3'>";
echo "<div class='card text-white bg-dark'>";
echo "<div class='card-body text-center'>";
echo "<h5 class='card-title'>致命错误</h5>";
echo "<p class='card-text display-6'>" . $result['stats']['fatal'] . "</p>";
echo "</div></div></div>";
echo "</div>";
// 显示详细错误
if (!empty($result['errors'])) {
echo "<h5>详细错误列表:</h5>";
echo "<table class='table table-bordered table-hover'>";
echo "<thead class='table-dark'>";
echo "<tr><th>#</th><th>级别</th><th>错误代码</th><th>消息</th><th>位置</th></tr>";
echo "</thead><tbody>";
foreach ($result['errors'] as $index => $error) {
$row_class = '';
if ($error['severity'] === LIBXML_ERR_FATAL) {
$row_class = 'table-danger';
} elseif ($error['severity'] === LIBXML_ERR_ERROR) {
$row_class = 'table-warning';
}
echo "<tr class='$row_class'>";
echo "<td>" . ($index + 1) . "</td>";
// 级别标签
$badge_class = 'bg-secondary';
if ($error['severity'] === LIBXML_ERR_FATAL) {
$badge_class = 'bg-danger';
} elseif ($error['severity'] === LIBXML_ERR_ERROR) {
$badge_class = 'bg-warning';
} elseif ($error['severity'] === LIBXML_ERR_WARNING) {
$badge_class = 'bg-info';
}
echo "<td><span class='badge $badge_class'>{$error['level']}</span></td>";
echo "<td><code>{$error['code']}</code></td>";
// 截断过长的错误消息
$message = htmlspecialchars($error['message']);
if (strlen($message) > 80) {
$message = substr($message, 0, 80) . '...';
}
echo "<td>$message</td>";
echo "<td>行: {$error['line']}, 列: " . ($error['column'] ?: '未知') . "</td>";
echo "</tr>";
}
echo "</tbody></table>";
// 显示错误代码统计
echo "<h5>按错误代码统计:</h5>";
echo "<table class='table table-sm table-bordered' style='width: auto;'>";
echo "<thead><tr><th>错误代码</th><th>出现次数</th></tr></thead>";
echo "<tbody>";
arsort($result['stats']['by_code']);
foreach ($result['stats']['by_code'] as $code => $count) {
echo "<tr><td><code>$code</code></td><td>$count</td></tr>";
}
echo "</tbody></table>";
}
// 清除错误缓冲区
libxml_clear_errors();
?>
下面的示例演示如何使用Schema验证XML,并获取详细的验证错误。
<?php
/**
* 验证XML是否符合Schema
*/
function validateXmlWithSchema($xml_string, $schema_string) {
// 启用内部错误处理
libxml_use_internal_errors(true);
libxml_clear_errors();
// 加载XML
$doc = new DOMDocument();
$doc->loadXML($xml_string);
// 加载Schema
$schema_doc = new DOMDocument();
$schema_doc->loadXML($schema_string);
// 验证
$is_valid = @$doc->schemaValidateSource($schema_string);
// 获取验证错误
$errors = libxml_get_errors();
return [
'valid' => $is_valid,
'errors' => $errors,
'document' => $doc
];
}
// XML Schema定义
$schema_xml = '<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employees">
<xs:complexType>
<xs:sequence>
<xs:element name="employee" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="age" type="xs:integer"/>
<xs:element name="department" type="xs:string"/>
<xs:element name="salary" type="xs:decimal" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="id" type="xs:integer" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>';
// 测试XML(包含多个错误)
$test_xml = '<?xml version="1.0" encoding="UTF-8"?>
<employees>
<employee id="101">
<name>张三</name>
<age>30</age>
<department>技术部</department>
<salary>5000.50</salary>
</employee>
<employee id="102">
<name>李四</name>
<age>二十五</age> <!-- 错误:年龄应该是整数 -->
<department>销售部</department>
<!-- 缺少salary元素 -->
</employee>
<employee> <!-- 错误:缺少id属性 -->
<name>王五</name>
<age>40</age>
<department>市场部</department>
<salary>invalid</salary> <!-- 错误:工资应该是数字 -->
</employee>
<unknown>未知元素</unknown> <!-- 错误:未在schema中定义 -->
</employees>';
echo "<h4>XML Schema验证:</h4>";
$result = validateXmlWithSchema($test_xml, $schema_xml);
if ($result['valid']) {
echo "<div class='alert alert-success'>XML符合Schema定义!</div>";
} else {
echo "<div class='alert alert-danger'>XML不符合Schema定义,发现 " . count($result['errors']) . " 个错误:</div>";
// 显示验证错误
echo "<table class='table table-bordered'>";
echo "<thead><tr><th>#</th><th>级别</th><th>错误代码</th><th>消息</th><th>位置</th></tr></thead>";
echo "<tbody>";
foreach ($result['errors'] as $index => $error) {
$level = '';
$row_class = '';
switch ($error->level) {
case LIBXML_ERR_WARNING:
$level = '警告';
$row_class = '';
break;
case LIBXML_ERR_ERROR:
$level = '错误';
$row_class = 'table-warning';
break;
case LIBXML_ERR_FATAL:
$level = '致命错误';
$row_class = 'table-danger';
break;
}
echo "<tr class='$row_class'>";
echo "<td>" . ($index + 1) . "</td>";
echo "<td>$level</td>";
echo "<td>{$error->code}</td>";
// 简化错误消息
$message = trim($error->message);
$message = preg_replace('/Element \{.*?\}:/', 'Element ', $message);
$message = preg_replace('/The value \'.*?\' of element .*? is not valid\./', '值不符合要求', $message);
echo "<td>" . htmlspecialchars($message) . "</td>";
echo "<td>行: {$error->line}, 列: " . ($error->column ?: '未知') . "</td>";
echo "</tr>";
}
echo "</tbody></table>";
// 错误分类
$error_types = [
'数据类型错误' => 0,
'缺少必需元素' => 0,
'结构错误' => 0,
'其他错误' => 0
];
foreach ($result['errors'] as $error) {
$message = $error->message;
if (strpos($message, 'is not a valid value') !== false ||
strpos($message, 'is not valid') !== false) {
$error_types['数据类型错误']++;
} elseif (strpos($message, 'missing') !== false ||
strpos($message, 'required') !== false) {
$error_types['缺少必需元素']++;
} elseif (strpos($message, 'element') !== false &&
strpos($message, 'not expected') !== false) {
$error_types['结构错误']++;
} else {
$error_types['其他错误']++;
}
}
echo "<h5>错误类型统计:</h5>";
echo "<div class='row'>";
$colors = ['primary', 'danger', 'warning', 'info'];
$color_index = 0;
foreach ($error_types as $type => $count) {
if ($count > 0) {
echo "<div class='col-md-3 mb-3'>";
echo "<div class='card bg-" . $colors[$color_index % count($colors)] . " text-white'>";
echo "<div class='card-body text-center'>";
echo "<h6 class='card-title'>$type</h6>";
echo "<p class='card-text h4'>$count</p>";
echo "</div></div></div>";
$color_index++;
}
}
echo "</div>";
}
// 清除错误缓冲区
libxml_clear_errors();
?>
下面的示例演示如何使用 libxml_get_errors() 处理HTML解析错误。
<?php
/**
* 解析HTML并处理错误
*/
function parseHtmlWithErrorHandling($html, $options = []) {
// 启用内部错误处理
libxml_use_internal_errors(true);
libxml_clear_errors();
$default_options = [
'encoding' => 'UTF-8',
'recover' => true, // 尝试从错误中恢复
'options' => LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
];
$options = array_merge($default_options, $options);
// 创建DOMDocument
$doc = new DOMDocument('1.0', $options['encoding']);
// 设置解析选项
if ($options['recover']) {
$doc->recover = true;
}
// 加载HTML(抑制警告)
$load_result = @$doc->loadHTML($html, $options['options']);
// 获取错误
$errors = libxml_get_errors();
// 格式化错误信息
$formatted_errors = [];
$has_fatal_error = false;
foreach ($errors as $error) {
// 检查是否为致命错误
if ($error->level === LIBXML_ERR_FATAL) {
$has_fatal_error = true;
}
// 简化HTML解析错误消息
$message = trim($error->message);
$message = str_replace('Tag ', '标签 ', $message);
$message = str_replace('invalid', '无效', $message);
$formatted_errors[] = [
'level' => $error->level,
'code' => $error->code,
'message' => $message,
'line' => $error->line,
'column' => $error->column,
'is_fatal' => ($error->level === LIBXML_ERR_FATAL)
];
}
return [
'success' => $load_result && !$has_fatal_error,
'document' => $doc,
'errors' => $formatted_errors,
'has_fatal_error' => $has_fatal_error,
'error_count' => count($errors)
];
}
// 测试HTML(包含多个错误)
$test_html = '<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>测试页面</title>
</head>
<body>
<h1>HTML解析测试</h1>
<!-- 常见的HTML错误 -->
<div>
<p>段落1
<p>段落2</p> <!-- 第一个p标签未闭合 -->
</div>
<!-- 无效的嵌套 -->
<p><div>无效的div在p中</div></p>
<!-- 重复的属性 -->
<div class="container" class="main">重复的class属性</div>
<!-- 特殊字符 -->
<p>特殊字符: & < > " </p>
<!-- 未闭合的标签 -->
<ul>
<li>项目1
<li>项目2</li>
</ul>
<!-- 未知标签 -->
<custom-tag>自定义标签</custom-tag>
</body>
</html>';
echo "<h4>HTML解析错误处理:</h4>";
$result = parseHtmlWithErrorHandling($test_html);
if ($result['success']) {
echo "<div class='alert alert-success'>HTML解析成功(尽管有" . $result['error_count'] . "个错误)</div>";
} else {
echo "<div class='alert alert-danger'>HTML解析失败,发现" . $result['error_count'] . "个错误</div>";
}
// 显示错误统计
echo "<h5>错误统计:</h5>";
echo "<table class='table table-bordered' style='width: auto;'>";
echo "<thead><tr><th>统计项</th><th>值</th></tr></thead>";
echo "<tbody>";
echo "<tr><td>总错误数</td><td>{$result['error_count']}</td></tr>";
echo "<tr><td>致命错误</td><td>" . ($result['has_fatal_error'] ? '有' : '无') . "</td></tr>";
echo "<tr><td>解析结果</td><td>" . ($result['success'] ? '成功' : '失败') . "</td></tr>";
echo "</tbody></table>";
// 显示错误详情
if (!empty($result['errors'])) {
echo "<h5>HTML解析错误详情:</h5>";
echo "<div style='max-height: 300px; overflow-y: auto;'>";
echo "<table class='table table-sm table-bordered'>";
echo "<thead><tr><th>#</th><th>级别</th><th>消息</th><th>位置</th><th>建议</th></tr></thead>";
echo "<tbody>";
$common_errors = [
'Tag p invalid' => '<p>标签必须正确闭合',
'div not allowed' => '<div>不能嵌套在<p>中',
'attribute class redefined' => '重复的属性,请删除一个',
'Tag li invalid' => '<li>标签必须正确闭合',
'Tag custom-tag invalid' => '使用有效的HTML5标签'
];
foreach ($result['errors'] as $index => $error) {
$level = '';
$row_class = '';
switch ($error['level']) {
case LIBXML_ERR_WARNING:
$level = '警告';
$row_class = '';
break;
case LIBXML_ERR_ERROR:
$level = '错误';
$row_class = 'table-warning';
break;
case LIBXML_ERR_FATAL:
$level = '致命错误';
$row_class = 'table-danger';
break;
}
echo "<tr class='$row_class'>";
echo "<td>" . ($index + 1) . "</td>";
echo "<td><span class='badge " . ($error['is_fatal'] ? 'bg-danger' : 'bg-warning') . "'>$level</span></td>";
echo "<td>" . htmlspecialchars($error['message']) . "</td>";
echo "<td>行: {$error['line']}</td>";
// 提供修复建议
$suggestion = '检查语法';
foreach ($common_errors as $pattern => $advice) {
if (strpos($error['message'], $pattern) !== false) {
$suggestion = $advice;
break;
}
}
echo "<td><small>$suggestion</small></td>";
echo "</tr>";
}
echo "</tbody></table>";
echo "</div>";
}
// 显示解析后的HTML(如果成功)
if ($result['success'] && $result['document']) {
echo "<h5>解析后的HTML(修复后):</h5>";
echo "<div style='max-height: 200px; overflow-y: auto; border: 1px solid #ddd; padding: 10px; background: #f8f9fa;'>";
$result['document']->formatOutput = true;
echo "<pre>" . htmlspecialchars($result['document']->saveHTML()) . "</pre>";
echo "</div>";
}
// 清除错误缓冲区
libxml_clear_errors();
?>
下面的示例演示如何在调试和生产环境中使用不同的错误处理策略。
<?php
/**
* XML处理器的生产环境配置
*/
class XmlProcessor {
private $debug_mode;
private $error_log_path;
private $max_errors_per_file;
public function __construct($debug_mode = false, $error_log_path = null) {
$this->debug_mode = $debug_mode;
$this->error_log_path = $error_log_path ?: sys_get_temp_dir() . '/xml_errors.log';
$this->max_errors_per_file = 100;
// 启用内部错误处理
libxml_use_internal_errors(true);
}
/**
* 安全解析XML(生产环境使用)
*/
public function safeParse($xml_content, $source = 'unknown') {
// 清除之前的错误
libxml_clear_errors();
try {
$doc = new DOMDocument();
// 安全设置:禁用外部实体加载
$old_entity_loader = libxml_disable_entity_loader(true);
// 尝试解析
$result = @$doc->loadXML($xml_content);
// 恢复实体加载器设置
libxml_disable_entity_loader($old_entity_loader);
if (!$result) {
$this->handleParseErrors($source);
return null;
}
return $doc;
} catch (Exception $e) {
$this->logError("解析异常: " . $e->getMessage(), $source);
return null;
}
}
/**
* 处理解析错误
*/
private function handleParseErrors($source) {
$errors = libxml_get_errors();
if (empty($errors)) {
return;
}
$error_count = count($errors);
// 调试模式:显示详细错误
if ($this->debug_mode) {
$this->displayDebugErrors($errors, $source);
}
// 生产环境:记录错误日志
$this->logErrors($errors, $source, $error_count);
// 清除错误缓冲区
libxml_clear_errors();
}
/**
* 调试模式显示错误
*/
private function displayDebugErrors($errors, $source) {
echo "<div class='alert alert-danger'>";
echo "<h5>XML解析错误(来源: $source)</h5>";
echo "<p>发现 " . count($errors) . " 个错误:</p>";
echo "<table class='table table-sm table-bordered'>";
echo "<thead><tr><th>级别</th><th>代码</th><th>消息</th><th>位置</th></tr></thead>";
echo "<tbody>";
foreach ($errors as $error) {
$level = $this->getErrorLevelName($error->level);
echo "<tr>";
echo "<td>$level</td>";
echo "<td>{$error->code}</td>";
// 截断过长的错误消息
$message = trim($error->message);
if (strlen($message) > 100) {
$message = substr($message, 0, 100) . '...';
}
echo "<td>" . htmlspecialchars($message) . "</td>";
echo "<td>行: {$error->line}</td>";
echo "</tr>";
}
echo "</tbody></table>";
echo "</div>";
}
/**
* 生产环境记录错误日志
*/
private function logErrors($errors, $source, $error_count) {
$log_entry = date('Y-m-d H:i:s') . " - 来源: $source - 错误数: $error_count\n";
// 只记录前N个错误,避免日志过大
$max_log_errors = min($error_count, $this->max_errors_per_file);
for ($i = 0; $i < $max_log_errors; $i++) {
$error = $errors[$i];
$level = $this->getErrorLevelName($error->level);
$message = trim($error->message);
$log_entry .= " 错误 #" . ($i + 1) . " [$level] [代码: {$error->code}] 行 {$error->line}: $message\n";
}
if ($error_count > $max_log_errors) {
$log_entry .= " 还有 " . ($error_count - $max_log_errors) . " 个错误未显示...\n";
}
$log_entry .= str_repeat('-', 80) . "\n";
// 写入日志文件
error_log($log_entry, 3, $this->error_log_path);
// 同时记录到系统日志(可选)
if ($error_count > 5) { // 只有错误较多时才记录到系统日志
$this->logError("XML解析失败: $source ($error_count 个错误)", $source);
}
}
/**
* 记录单个错误
*/
private function logError($message, $source) {
$log_message = date('Y-m-d H:i:s') . " [$source] $message\n";
error_log($log_message, 3, $this->error_log_path);
}
/**
* 获取错误级别名称
*/
private function getErrorLevelName($level) {
static $level_names = [
LIBXML_ERR_WARNING => '警告',
LIBXML_ERR_ERROR => '错误',
LIBXML_ERR_FATAL => '致命错误'
];
return $level_names[$level] ?? '未知级别';
}
/**
* 获取错误统计信息
*/
public function getErrorStats() {
$log_content = @file_get_contents($this->error_log_path);
if (!$log_content) {
return ['total_entries' => 0, 'last_error' => null];
}
$lines = explode("\n", $log_content);
$entry_count = 0;
foreach ($lines as $line) {
if (strpos($line, '来源:') !== false) {
$entry_count++;
}
}
return [
'total_entries' => $entry_count,
'last_error' => end($lines),
'log_size' => round(strlen($log_content) / 1024, 2) . ' KB'
];
}
}
// 演示不同环境下的处理
echo "<h4>XML错误处理策略演示:</h4>";
// 模拟不同环境
$environments = [
'debug' => true,
'production' => false
];
foreach ($environments as $env_name => $is_debug) {
echo "<h5>环境: " . ($is_debug ? '调试模式' : '生产模式') . "</h5>";
$processor = new XmlProcessor($is_debug);
// 测试XML(包含错误)
$test_xml = '<?xml version="1.0"?>
<data>
<item id="1">正常数据</item>
<item>缺少id属性</item>
<item id="invalid">无效ID<item> <!-- 未闭合标签 -->
<unknown>未知元素</unknown>
</data>';
echo "<p>解析测试XML...</p>";
$result = $processor->safeParse($test_xml, "test_$env_name");
if ($result) {
echo "<div class='alert alert-success'>解析成功</div>";
} else {
echo "<div class='alert alert-danger'>解析失败" . ($is_debug ? '' : '(错误已记录到日志)') . "</div>";
}
// 显示错误统计(生产环境)
if (!$is_debug) {
$stats = $processor->getErrorStats();
echo "<div class='alert alert-info'>";
echo "错误日志统计: ";
echo "总条目: {$stats['total_entries']}, ";
echo "日志大小: {$stats['log_size']}";
echo "</div>";
}
echo "<hr>";
}
// 最佳实践建议
echo "<h4>libxml错误处理最佳实践:</h4>";
echo "<div class='alert alert-info'>";
echo "<ul>";
echo "<li><strong>始终启用内部错误处理</strong>:使用 <code>libxml_use_internal_errors(true)</code> 避免错误直接输出</li>";
echo "<li><strong>及时清除错误缓冲区</strong>:使用 <code>libxml_clear_errors()</code> 防止错误累积</li>";
echo "<li><strong>分类处理错误</strong>:根据错误级别(警告、错误、致命错误)采取不同策略</li>";
echo "<li><strong>环境适配</strong>:调试环境显示详细错误,生产环境记录到日志</li>";
echo "<li><strong>安全性考虑</strong>:使用 <code>libxml_disable_entity_loader(true)</code> 防止XXE攻击</li>";
echo "<li><strong>性能优化</strong>:批量处理时定期清除错误缓冲区,避免内存泄漏</li>";
echo "</ul>";
echo "</div>";
// 清除全局错误缓冲区
libxml_clear_errors();
?>
libxml_get_errors()获取错误后,应使用libxml_clear_errors()清除缓冲区。