libxml_use_internal_errors() 函数用于启用或禁用 libxml 内部错误处理。当启用内部错误处理时,libxml 不会直接将解析错误输出到屏幕或抛出异常,而是将错误信息存储在内部缓冲区中,可以通过 libxml_get_errors() 函数获取。
libxml_clear_errors() 清除缓冲区,避免内存泄漏。
libxml_use_internal_errors ( bool $use_errors = false ) : bool
参数说明:
| 参数 | 说明 | 必需 | 默认值 |
|---|---|---|---|
$use_errors |
是否启用内部错误处理。 true: 启用内部错误处理 false: 禁用内部错误处理 |
否 | false |
函数返回之前内部错误处理状态的布尔值:
$previous_state = libxml_use_internal_errors(true);
// 如果之前是禁用状态,$previous_state 为 false
// 现在启用了内部错误处理
下面的示例演示如何启用内部错误处理,并捕获XML解析错误。
<?php
// 保存之前的错误处理状态
$previous_state = libxml_use_internal_errors(true);
echo "之前的内部错误处理状态: " . ($previous_state ? '启用' : '禁用') . "<br>";
echo "当前内部错误处理状态: " . (libxml_use_internal_errors() ? '启用' : '禁用') . "<br>";
// 创建一个格式错误的XML
$malformed_xml = '<root><item>第一个项目</item><item>第二个项目<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 $error) {
echo "<div class='alert alert-warning'>";
echo "<strong>错误级别:</strong> ";
switch ($error->level) {
case LIBXML_ERR_WARNING: echo '警告'; break;
case LIBXML_ERR_ERROR: echo '错误'; break;
case LIBXML_ERR_FATAL: echo '致命错误'; break;
default: echo '未知'; break;
}
echo "<br><strong>错误代码:</strong> {$error->code}<br>";
echo "<strong>错误消息:</strong> " . htmlspecialchars(trim($error->message)) . "<br>";
echo "<strong>位置:</strong> 行 {$error->line}, 列 " . ($error->column ?: '未知');
echo "</div>";
}
// 清除错误缓冲区
libxml_clear_errors();
} else {
echo "<div class='alert alert-success'>XML解析成功!</div>";
}
// 恢复之前的错误处理状态(可选)
// libxml_use_internal_errors($previous_state);
?>
下面的示例演示启用和禁用内部错误处理时的不同行为。
<?php
// 测试XML(包含错误)
$test_xml = '<root><item>未闭合标签</root>';
echo "<h4>对比启用和禁用内部错误处理:</h4>";
// 场景1:禁用内部错误处理(默认状态)
echo "<h5>场景1:禁用内部错误处理(默认)</h5>";
echo "<p>此时错误可能会直接输出到屏幕或触发警告</p>";
// 禁用内部错误处理
libxml_use_internal_errors(false);
// 尝试解析(可能会产生输出)
$doc1 = new DOMDocument();
echo "<div style='border: 1px solid #ddd; padding: 10px; margin-bottom: 20px; background: #f8f9fa;'>";
echo "<strong>解析结果:</strong> ";
$result1 = @$doc1->loadXML($test_xml); // 使用 @ 抑制错误输出
echo $result1 ? '成功' : '失败';
echo "</div>";
// 场景2:启用内部错误处理
echo "<h5>场景2:启用内部错误处理</h5>";
echo "<p>此时错误被收集到内部缓冲区,不会直接输出</p>";
// 启用内部错误处理
libxml_use_internal_errors(true);
libxml_clear_errors(); // 清除之前的错误
$doc2 = new DOMDocument();
echo "<div style='border: 1px solid #ddd; padding: 10px; margin-bottom: 20px; background: #f8f9fa;'>";
echo "<strong>解析结果:</strong> ";
$result2 = $doc2->loadXML($test_xml);
echo $result2 ? '成功' : '失败';
echo "</div>";
// 获取并显示错误
if (!$result2) {
$errors = libxml_get_errors();
echo "<div class='alert alert-info'>";
echo "<strong>收集到的错误(" . count($errors) . "个):</strong><br>";
foreach ($errors as $index => $error) {
echo ($index + 1) . ". " . htmlspecialchars(trim($error->message)) . "<br>";
}
echo "</div>";
// 清除错误缓冲区
libxml_clear_errors();
}
// 总结对比
echo "<h5>总结对比:</h5>";
echo "<table class='table table-bordered'>";
echo "<thead><tr><th>场景</th><th>错误处理方式</th><th>错误输出</th><th>错误访问</th><th>适用场景</th></tr></thead>";
echo "<tbody>";
echo "<tr><td>禁用内部错误处理</td><td>直接输出/触发警告</td><td>直接可见</td><td>不可访问</td><td>调试、开发环境</td></tr>";
echo "<tr><td>启用内部错误处理</td><td>收集到缓冲区</td><td>不输出</td><td>可通过函数访问</td><td>生产环境、需要程序化处理错误</td></tr>";
echo "</tbody></table>";
// 最佳实践建议
echo "<div class='alert alert-success mt-3'>";
echo "<strong>最佳实践建议:</strong>";
echo "<ul class='mb-0'>";
echo "<li>生产环境建议启用内部错误处理,避免错误直接暴露给用户</li>";
echo "<li>开发环境可以根据需要选择启用或禁用</li>";
echo "<li>启用内部错误处理后,记得定期调用 <code>libxml_clear_errors()</code> 清理缓冲区</li>";
echo "<li>在需要获取错误详情时使用 <code>libxml_get_errors()</code> 或 <code>libxml_get_last_error()</code></li>";
echo "</ul>";
echo "</div>";
?>
下面的示例演示在进行XML Schema或DTD验证时如何使用内部错误处理。
<?php
/**
* 验证XML并处理验证错误
*/
function validateXml($xml_string, $schema_string = null) {
// 启用内部错误处理
libxml_use_internal_errors(true);
libxml_clear_errors();
$doc = new DOMDocument();
$doc->loadXML($xml_string);
$is_valid = true;
$validation_errors = [];
// 如果有Schema,进行Schema验证
if ($schema_string !== null) {
$is_valid = $doc->schemaValidateSource($schema_string);
} else {
// 否则进行DTD验证
$is_valid = $doc->validate();
}
// 获取验证错误
if (!$is_valid) {
$errors = libxml_get_errors();
foreach ($errors as $error) {
$validation_errors[] = [
'level' => $error->level,
'code' => $error->code,
'message' => trim($error->message),
'line' => $error->line,
'column' => $error->column
];
}
}
// 清除错误缓冲区
libxml_clear_errors();
return [
'valid' => $is_valid,
'errors' => $validation_errors,
'document' => $doc
];
}
// XML Schema定义
$schema = '<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="age" type="xs:integer"/>
<xs:element name="email" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>';
// 测试XML(包含验证错误)
$test_xml = '<?xml version="1.0"?>
<person>
<name>张三</name>
<age>not_a_number</age> <!-- 错误:年龄应该是整数 -->
<email>invalid-email</email> <!-- 错误:邮箱格式不正确 -->
<extra>多余的元素</extra> <!-- 错误:未在Schema中定义 -->
</person>';
echo "<h4>XML Schema验证和错误处理:</h4>";
$result = validateXml($test_xml, $schema);
if ($result['valid']) {
echo "<div class='alert alert-success'>XML验证通过!</div>";
} else {
echo "<div class='alert alert-danger'>XML验证失败,发现 " . count($result['errors']) . " 个错误:</div>";
// 显示详细错误信息
echo "<table class='table table-bordered table-hover'>";
echo "<thead class='table-dark'>";
echo "<tr><th>#</th><th>级别</th><th>错误消息</th><th>位置</th></tr>";
echo "</thead><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><span class='badge " . ($level === '致命错误' ? 'bg-danger' : ($level === '错误' ? 'bg-warning' : 'bg-info')) . "'>$level</span></td>";
// 简化错误消息
$message = htmlspecialchars($error['message']);
$message = preg_replace('/Element \{.*?\}:/', '', $message);
echo "<td>$message</td>";
echo "<td>行: {$error['line']}</td>";
echo "</tr>";
}
echo "</tbody></table>";
// 错误分类统计
$error_stats = [
'数据类型错误' => 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_stats['数据类型错误']++;
} elseif (strpos($message, 'element') !== false && strpos($message, 'not expected') !== false) {
$error_stats['结构错误']++;
} elseif (strpos($message, 'missing') !== false || strpos($message, 'required') !== false) {
$error_stats['约束错误']++;
} else {
$error_stats['其他错误']++;
}
}
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>";
foreach ($error_stats as $type => $count) {
if ($count > 0) {
echo "<tr><td>$type</td><td>$count</td></tr>";
}
}
echo "</tbody></table>";
}
// XML验证最佳实践
echo "<div class='alert alert-info mt-3'>";
echo "<strong>XML验证最佳实践:</strong>";
echo "<ul class='mb-0'>";
echo "<li>始终在验证前启用内部错误处理</li>";
echo "<li>验证后立即获取错误信息,避免被后续操作覆盖</li>";
echo "<li>根据错误级别采取不同的处理策略</li>";
echo "<li>对于用户提供的XML,提供友好的错误提示</li>";
echo "<li>生产环境中记录验证错误以便排查问题</li>";
echo "</ul>";
echo "</div>";
?>
下面的示例演示在解析HTML时如何使用内部错误处理,并利用libxml的恢复功能。
<?php
/**
* 安全解析HTML,处理错误并尝试恢复
*/
function parseHtmlSafely($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);
$doc = new DOMDocument('1.0', $options['encoding']);
// 启用恢复模式(libxml会尝试从错误中恢复)
if ($options['recover']) {
$doc->recover = true;
}
// 加载HTML
$load_result = @$doc->loadHTML($html, $options['options']);
// 获取错误信息
$errors = libxml_get_errors();
// 分析错误
$error_analysis = [
'total' => count($errors),
'warnings' => 0,
'errors' => 0,
'fatal' => 0,
'recovered' => false
];
foreach ($errors as $error) {
switch ($error->level) {
case LIBXML_ERR_WARNING: $error_analysis['warnings']++; break;
case LIBXML_ERR_ERROR: $error_analysis['errors']++; break;
case LIBXML_ERR_FATAL: $error_analysis['fatal']++; break;
}
}
// 判断是否从错误中恢复了
$error_analysis['recovered'] = ($load_result || ($options['recover'] && $doc->documentElement !== null));
// 清除错误缓冲区
libxml_clear_errors();
return [
'success' => $load_result,
'document' => $doc,
'errors' => $errors,
'analysis' => $error_analysis,
'recovered' => $error_analysis['recovered']
];
}
// 测试HTML(包含多个错误)
$test_html = '<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>测试页面</title>
</head>
<body>
<h1>HTML测试</h1>
<!-- 常见的HTML错误 -->
<div class=container> <!-- 属性值缺少引号 -->
<p>第一个段落
<p>第二个段落</p> <!-- 第一个p标签未闭合 -->
<img src="image.jpg"> <!-- img标签没有alt属性 -->
</div>
<ul>
<li>项目1
<li>项目2</li>
</ul>
<script>
// JavaScript代码
console.log("测试");
</script>
</body>
</html>';
echo "<h4>HTML解析错误处理和恢复:</h4>";
// 测试不同的解析模式
$test_modes = [
'严格模式(禁用恢复)' => ['recover' => false],
'宽松模式(启用恢复)' => ['recover' => true],
'快速模式(最小化错误检查)' => ['recover' => true, 'options' => LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOERROR | LIBXML_NOWARNING]
];
foreach ($test_modes as $mode_name => $mode_options) {
echo "<h5>模式:$mode_name</h5>";
$result = parseHtmlSafely($test_html, $mode_options);
// 显示错误分析
echo "<table class='table table-sm table-bordered' style='width: auto;'>";
echo "<thead><tr><th>分析项</th><th>值</th></tr></thead>";
echo "<tbody>";
$analysis = $result['analysis'];
echo "<tr><td>总错误数</td><td>{$analysis['total']}</td></tr>";
echo "<tr><td>警告数</td><td>{$analysis['warnings']}</td></tr>";
echo "<tr><td>错误数</td><td>{$analysis['errors']}</td></tr>";
echo "<tr><td>致命错误数</td><td>{$analysis['fatal']}</td></tr>";
echo "<tr><td>是否恢复</td><td>" . ($analysis['recovered'] ? '是' : '否') . "</td></tr>";
echo "<tr><td>解析成功</td><td>" . ($result['success'] ? '是' : '否') . "</td></tr>";
echo "</tbody></table>";
// 显示示例错误(如果有)
if (!empty($result['errors']) && $analysis['total'] > 0) {
echo "<p><strong>示例错误:</strong></p>";
$sample_count = min(2, count($result['errors']));
for ($i = 0; $i < $sample_count; $i++) {
$error = $result['errors'][$i];
echo "<div class='alert alert-warning' style='font-size: 0.9em;'>";
echo htmlspecialchars(trim($error->message));
echo "</div>";
}
if ($analysis['total'] > $sample_count) {
echo "<p><small>还有 " . ($analysis['total'] - $sample_count) . " 个错误未显示...</small></p>";
}
}
// 显示解析结果(如果成功)
if ($result['recovered'] || $result['success']) {
echo "<p><strong>解析结果:</strong> ";
echo "HTML文档" . ($result['document']->documentElement ? "包含 " . $result['document']->getElementsByTagName('*')->length . " 个元素" : "为空");
echo "</p>";
}
echo "<hr>";
}
// HTML解析特点说明
echo "<div class='alert alert-info mt-3'>";
echo "<strong>HTML解析的特点:</strong>";
echo "<ul class='mb-0'>";
echo "<li>HTML解析器比XML解析器更宽容,会自动修复许多常见错误</li>";
echo "<li>启用恢复模式(recover)可以让解析器从致命错误中恢复</li>";
echo "<li>LIBXML_NOERROR 和 LIBXML_NOWARNING 选项可以抑制错误报告</li>";
echo "<li>即使有解析错误,通常也能获得可用的DOM文档</li>";
echo "<li>对于用户输入的HTML,通常使用宽松模式以获得更好的兼容性</li>";
echo "</ul>";
echo "</div>";
// 实用函数示例
echo "<h5>实用函数 - 清理和修复HTML:</h5>";
echo "<pre><code class='language-php'>/**
* 清理和修复HTML
*/
function cleanHtml($html) {
// 启用内部错误处理,但不显示错误
libxml_use_internal_errors(true);
\$doc = new DOMDocument('1.0', 'UTF-8');
\$doc->recover = true; // 启用恢复
// 加载HTML,抑制错误
@\$doc->loadHTML(\$html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
// 清除错误缓冲区
libxml_clear_errors();
// 返回清理后的HTML
return \$doc->saveHTML();
}
// 使用示例
\$dirty_html = '<div><p>未闭合段落<div>错误嵌套</p></div>';
\$clean_html = cleanHtml(\$dirty_html);
echo \$clean_html;</code></pre>";
?>
下面的示例演示在生产环境中如何使用 libxml_use_internal_errors() 实现健壮的错误处理。
<?php
/**
* 生产环境XML处理器
*/
class ProductionXmlProcessor {
private $config;
private $error_logger;
public function __construct($config = []) {
$this->config = array_merge([
'enable_internal_errors' => true,
'log_level' => 'error', // error, warning, all, none
'max_errors_per_request' => 100,
'throw_exceptions' => false,
'error_log_path' => null
], $config);
// 初始化错误记录器
$this->error_logger = new ErrorLogger($this->config['error_log_path']);
}
/**
* 安全解析XML
*/
public function safeParse($xml_string, $context = '') {
// 设置错误处理状态
$previous_state = libxml_use_internal_errors($this->config['enable_internal_errors']);
try {
// 清除之前的错误
libxml_clear_errors();
$doc = new DOMDocument();
// 安全设置:禁用外部实体加载
$old_entity_loader = libxml_disable_entity_loader(true);
// 尝试解析
$result = $doc->loadXML($xml_string);
// 恢复实体加载器
libxml_disable_entity_loader($old_entity_loader);
if (!$result) {
return $this->handleParseFailure($doc, $context);
}
return [
'success' => true,
'document' => $doc,
'errors' => []
];
} catch (Exception $e) {
// 恢复之前的错误处理状态
libxml_use_internal_errors($previous_state);
return $this->handleException($e, $context);
}
}
/**
* 处理解析失败
*/
private function handleParseFailure($doc, $context) {
$errors = libxml_get_errors();
// 限制错误数量
if (count($errors) > $this->config['max_errors_per_request']) {
$errors = array_slice($errors, 0, $this->config['max_errors_per_request']);
}
// 记录错误
$this->logErrors($errors, $context);
// 清除错误缓冲区
libxml_clear_errors();
// 准备返回结果
$result = [
'success' => false,
'document' => null,
'errors' => $errors
];
// 如果需要抛出异常
if ($this->config['throw_exceptions'] && !empty($errors)) {
$first_error = $errors[0];
throw new XmlParseException(
"XML解析失败: " . trim($first_error->message),
$first_error->code,
null,
$first_error->line
);
}
return $result;
}
/**
* 记录错误
*/
private function logErrors($errors, $context) {
if ($this->config['log_level'] === 'none') {
return;
}
foreach ($errors as $error) {
// 根据配置决定记录哪些级别的错误
if ($this->config['log_level'] === 'error' && $error->level < LIBXML_ERR_ERROR) {
continue;
}
if ($this->config['log_level'] === 'warning' && $error->level === LIBXML_ERR_FATAL) {
continue;
}
$this->error_logger->logXmlError($error, $context);
}
}
/**
* 处理异常
*/
private function handleException($exception, $context) {
$this->error_logger->logException($exception, $context);
return [
'success' => false,
'document' => null,
'errors' => [],
'exception' => $exception->getMessage()
];
}
/**
* 批量处理XML
*/
public function batchParse($xml_items, $context = '') {
$results = [];
$stats = [
'total' => 0,
'success' => 0,
'failed' => 0
];
foreach ($xml_items as $id => $xml) {
$result = $this->safeParse($xml, $context . " [item: $id]");
$results[$id] = $result;
$stats['total']++;
if ($result['success']) {
$stats['success']++;
} else {
$stats['failed']++;
}
}
return [
'results' => $results,
'stats' => $stats
];
}
}
/**
* 错误记录器
*/
class ErrorLogger {
private $log_file;
public function __construct($log_file = null) {
$this->log_file = $log_file ?: sys_get_temp_dir() . '/xml_errors.log';
}
/**
* 记录XML错误
*/
public function logXmlError($error, $context) {
$level = $this->getErrorLevelName($error->level);
$timestamp = date('Y-m-d H:i:s');
$log_entry = sprintf(
"[%s] [%s] [代码: %d] %s (行: %d) - 上下文: %s\n",
$timestamp,
$level,
$error->code,
trim($error->message),
$error->line,
$context
);
error_log($log_entry, 3, $this->log_file);
}
/**
* 记录异常
*/
public function logException($exception, $context) {
$timestamp = date('Y-m-d H:i:s');
$log_entry = sprintf(
"[%s] [EXCEPTION] %s (文件: %s, 行: %d) - 上下文: %s\n",
$timestamp,
$exception->getMessage(),
$exception->getFile(),
$exception->getLine(),
$context
);
error_log($log_entry, 3, $this->log_file);
}
/**
* 获取错误级别名称
*/
private function getErrorLevelName($level) {
switch ($level) {
case LIBXML_ERR_WARNING: return 'WARNING';
case LIBXML_ERR_ERROR: return 'ERROR';
case LIBXML_ERR_FATAL: return 'FATAL';
default: return 'UNKNOWN';
}
}
}
/**
* XML解析异常类
*/
class XmlParseException extends Exception {
private $line_number;
public function __construct($message, $code = 0, $previous = null, $line_number = null) {
parent::__construct($message, $code, $previous);
$this->line_number = $line_number;
}
public function getLineNumber() {
return $this->line_number;
}
}
// 演示生产环境使用
echo "<h4>生产环境XML处理演示:</h4>";
// 配置处理器
$processor = new ProductionXmlProcessor([
'enable_internal_errors' => true,
'log_level' => 'error',
'max_errors_per_request' => 10,
'throw_exceptions' => false,
'error_log_path' => '/tmp/xml_production_errors.log'
]);
// 测试数据
$test_xmls = [
'correct' => '<?xml version="1.0"?><root><item>正确XML</item></root>',
'malformed' => '<root><item>未闭合标签</root>',
'invalid' => '<root><item attribute=value>属性错误</item></root>'
];
// 批量处理
$batch_result = $processor->batchParse($test_xmls, '批量测试');
// 显示结果
echo "<h5>处理结果:</h5>";
echo "<table class='table table-bordered'>";
echo "<thead><tr><th>XML ID</th><th>状态</th><th>错误数</th></tr></thead>";
echo "<tbody>";
foreach ($batch_result['results'] as $id => $result) {
echo "<tr>";
echo "<td>$id</td>";
if ($result['success']) {
echo "<td><span class='badge bg-success'>成功</span></td>";
echo "<td>0</td>";
} else {
echo "<td><span class='badge bg-danger'>失败</span></td>";
echo "<td>" . count($result['errors']) . "</td>";
}
echo "</tr>";
}
echo "</tbody></table>";
// 显示统计
$stats = $batch_result['stats'];
echo "<div class='alert alert-info'>";
echo "<strong>处理统计:</strong> ";
echo "总数: {$stats['total']}, ";
echo "成功: {$stats['success']}, ";
echo "失败: {$stats['failed']}";
echo "</div>";
// 显示错误日志示例
echo "<h5>错误日志示例:</h5>";
echo "<div class='alert alert-light' style='font-family: monospace; font-size: 0.9em;'>";
echo "[2023-10-01 12:30:45] [ERROR] [代码: 76] Opening and ending tag mismatch: item line 1 and root (行: 1) - 上下文: 批量测试 [item: malformed]<br>";
echo "[2023-10-01 12:30:46] [ERROR] [代码: 39] Specification mandate value for attribute attribute (行: 1) - 上下文: 批量测试 [item: invalid]";
echo "</div>";
// 生产环境最佳实践
echo "<div class='alert alert-success mt-3'>";
echo "<strong>生产环境最佳实践:</strong>";
echo "<ul class='mb-0'>";
echo "<li>始终启用内部错误处理,避免错误直接暴露</li>";
echo "<li>实现完善的错误记录机制</li>";
echo "<li>限制单次请求的最大错误数量,防止内存溢出</li>";
echo "<li>考虑使用异常和普通错误处理两种机制</li>";
echo "<li>定期清理错误日志,避免磁盘空间不足</li>";
echo "<li>监控错误率,及时发现系统问题</li>";
echo "</ul>";
echo "</div>";
// 配置建议
echo "<h5>不同环境的配置建议:</h5>";
echo "<table class='table table-bordered table-sm'>";
echo "<thead><tr><th>环境</th><th>enable_internal_errors</th><th>log_level</th><th>throw_exceptions</th></tr></thead>";
echo "<tbody>";
echo "<tr><td>开发环境</td><td>true(可查看详细错误)</td><td>all(记录所有错误)</td><td>false(便于调试)</td></tr>";
echo "<tr><td>测试环境</td><td>true</td><td>error(只记录错误)</td><td>true(测试异常处理)</td></tr>";
echo "<tr><td>生产环境</td><td>true</td><td>error</td><td>false(避免中断服务)</td></tr>";
echo "</tbody></table>";
?>
libxml_use_internal_errors() 的设置是全局的,会影响之后所有使用 libxml 的操作。libxml_clear_errors() 清理,避免内存泄漏。@ 只能抑制错误输出,而启用内部错误处理可以收集和访问错误信息。