Files
kiri-router/src/template/error.php
T

499 lines
14 KiB
PHP
Raw Normal View History

2025-12-31 00:19:29 +08:00
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>Error: <?= htmlspecialchars($errorData['type']) ?></title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #333;
line-height: 1.6;
min-height: 100vh;
padding: 20px;
}
.error-container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 10px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
overflow: hidden;
}
.error-header {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
padding: 20px 30px;
}
.error-title {
font-size: 24px;
margin-bottom: 5px;
display: flex;
align-items: center;
gap: 10px;
}
.error-title i {
font-size: 28px;
}
.error-subtitle {
font-size: 14px;
opacity: 0.9;
}
.error-content {
padding: 30px;
}
.error-section {
margin-bottom: 30px;
border: 1px solid #e0e0e0;
border-radius: 8px;
overflow: hidden;
}
.section-header {
background: #f5f5f5;
padding: 15px 20px;
border-bottom: 1px solid #e0e0e0;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
transition: background 0.3s;
}
.section-header:hover {
background: #e8e8e8;
}
.section-title {
font-weight: bold;
color: #333;
}
.section-toggle {
color: #666;
font-size: 12px;
}
.section-content {
padding: 20px;
background: white;
}
.code-block {
background: #282c34;
color: #abb2bf;
padding: 15px;
border-radius: 5px;
overflow-x: auto;
font-size: 14px;
margin: 10px 0;
}
.file-path {
color: #61afef;
font-weight: bold;
}
.line-number {
color: #98c379;
}
.error-message {
color: #e06c75;
font-weight: bold;
}
table {
width: 100%;
border-collapse: collapse;
margin: 10px 0;
}
th, td {
padding: 10px;
text-align: left;
border-bottom: 1px solid #e0e0e0;
}
th {
background: #f5f5f5;
font-weight: bold;
}
tr:hover {
background: #f9f9f9;
}
.trace-item {
margin-bottom: 15px;
padding: 10px;
background: #f8f9fa;
border-left: 4px solid #667eea;
border-radius: 0 4px 4px 0;
}
.trace-header {
font-weight: bold;
color: #333;
margin-bottom: 5px;
}
.trace-location {
color: #666;
font-size: 12px;
}
.badge {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
margin-right: 5px;
}
.badge-error {
background: #f44336;
color: white;
}
.badge-warning {
background: #ff9800;
color: white;
}
.badge-info {
background: #2196f3;
color: white;
}
.badge-success {
background: #4caf50;
color: white;
}
.environment-info {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-top: 20px;
}
.info-item {
background: #f8f9fa;
padding: 15px;
border-radius: 5px;
border-left: 4px solid #667eea;
}
.info-label {
font-size: 12px;
color: #666;
text-transform: uppercase;
margin-bottom: 5px;
}
.info-value {
font-weight: bold;
color: #333;
}
.actions {
display: flex;
gap: 10px;
margin-top: 20px;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 5px;
}
.btn-primary {
background: #667eea;
color: white;
}
.btn-primary:hover {
background: #5a6fd8;
transform: translateY(-2px);
}
.btn-secondary {
background: #6c757d;
color: white;
}
.btn-secondary:hover {
background: #5a6268;
transform: translateY(-2px);
}
@media (max-width: 768px) {
.error-container {
border-radius: 0;
}
.environment-info {
grid-template-columns: 1fr;
}
}
.hidden {
display: none;
}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
<div class="error-container">
<div class="error-header">
<h1 class="error-title">
<i class="fas fa-exclamation-triangle"></i>
<?= htmlspecialchars($errorData['type']) ?>
</h1>
<div class="error-subtitle">
<?= htmlspecialchars($errorData['message']) ?>
</div>
</div>
<div class="error-content">
<!-- Error Details -->
<div class="error-section">
<div class="section-header" onclick="toggleSection('details')">
<span class="section-title">Error Details</span>
<span class="section-toggle" id="toggle-details">▼</span>
</div>
<div class="section-content" id="section-details">
<div class="code-block">
<span class="file-path"><?= htmlspecialchars($errorData['file']) ?></span>
<span class="line-number">:<?= $errorData['line'] ?></span>
<br><br>
<span class="error-message"><?= htmlspecialchars($errorData['message']) ?></span>
</div>
<table>
<tr>
<th>Type</th>
<td><span class="badge badge-error"><?= htmlspecialchars($errorData['type']) ?></span></td>
</tr>
<tr>
<th>Code</th>
<td><?= $errorData['code'] ?></td>
</tr>
<tr>
<th>Timestamp</th>
<td><?= $errorData['timestamp'] ?></td>
</tr>
</table>
</div>
</div>
<!-- Stack Trace -->
<div class="error-section">
<div class="section-header" onclick="toggleSection('trace')">
<span class="section-title">Stack Trace</span>
<span class="section-toggle" id="toggle-trace">▼</span>
</div>
<div class="section-content" id="section-trace">
<?php
foreach ($errorData['trace'] as $index => $trace): ?>
<div class="trace-item">
<div class="trace-header">
#<?= $index ?>:
<?= $trace['class'] ?? '' ?><?= $trace['type'] ?? '' ?><?= $trace['function'] ?>()
</div>
<div class="trace-location">
<?= $trace['file'] ?? 'internal' ?><?= isset($trace['line']) ? ':' . $trace['line'] : '' ?>
</div>
<?php
if (!empty($trace['args'])): ?>
<div style="margin-top: 5px; font-size: 12px; color: #666;">
Arguments: <?= implode(', ', $trace['args']) ?>
</div>
<?php
endif; ?>
</div>
<?php
endforeach; ?>
</div>
</div>
<!-- Server Information -->
<div class="error-section">
<div class="section-header" onclick="toggleSection('server')">
<span class="section-title">Server Information</span>
<span class="section-toggle" id="toggle-server">▼</span>
</div>
<div class="section-content hidden" id="section-server">
<table>
<?php
foreach ($errorData['server'] as $key => $value): ?>
<tr>
<th><?= htmlspecialchars($key) ?></th>
<td><?= htmlspecialchars($value) ?></td>
</tr>
<?php
endforeach; ?>
</table>
</div>
</div>
<!-- Request Information -->
<div class="error-section">
<div class="section-header" onclick="toggleSection('request')">
<span class="section-title">Request Information</span>
<span class="section-toggle" id="toggle-request">▼</span>
</div>
<div class="section-content hidden" id="section-request">
<h4>GET Parameters</h4>
<?php
if (!empty($errorData['request']['GET'])): ?>
<table>
<?php
foreach ($errorData['request']['GET'] as $key => $value): ?>
<tr>
<th><?= htmlspecialchars($key) ?></th>
<td><?= htmlspecialchars(is_array($value) ? json_encode($value) : $value) ?></td>
</tr>
<?php
endforeach; ?>
</table>
<?php
else: ?>
<p>No GET parameters</p>
<?php
endif; ?>
<h4>POST Parameters</h4>
<?php
if (!empty($errorData['request']['POST'])): ?>
<table>
<?php
foreach ($errorData['request']['POST'] as $key => $value): ?>
<tr>
<th><?= htmlspecialchars($key) ?></th>
<td><?= htmlspecialchars(is_array($value) ? json_encode($value) : $value) ?></td>
</tr>
<?php
endforeach; ?>
</table>
<?php
else: ?>
<p>No POST parameters</p>
<?php
endif; ?>
</div>
</div>
<!-- Environment Info -->
<div class="environment-info">
<div class="info-item">
<div class="info-label">Memory Usage</div>
<div class="info-value"><?= $errorData['memory_usage'] ?></div>
</div>
<div class="info-item">
<div class="info-label">Peak Memory</div>
<div class="info-value"><?= $errorData['peak_memory'] ?></div>
</div>
<div class="info-item">
<div class="info-label">Execution Time</div>
<div class="info-value"><?= round($errorData['execution_time'], 4) ?> seconds</div>
</div>
<div class="info-item">
<div class="info-label">PHP Version</div>
<div class="info-value"><?= PHP_VERSION ?></div>
</div>
</div>
<!-- Actions -->
<div class="actions">
<button class="btn btn-primary" onclick="window.location.reload()">
<i class="fas fa-redo"></i> Reload Page
</button>
<button class="btn btn-secondary" onclick="window.history.back()">
<i class="fas fa-arrow-left"></i> Go Back
</button>
<a href="/" class="btn btn-secondary">
<i class="fas fa-home"></i> Go Home
</a>
<button class="btn btn-secondary" onclick="copyErrorDetails()">
<i class="fas fa-copy"></i> Copy Error Details
</button>
</div>
</div>
</div>
<script>
function toggleSection(sectionId) {
const section = document.getElementById(`section-${sectionId}`);
const toggle = document.getElementById(`toggle-${sectionId}`);
if (section.classList.contains('hidden')) {
section.classList.remove('hidden');
toggle.textContent = '▲';
} else {
section.classList.add('hidden');
toggle.textContent = '▼';
}
}
function copyErrorDetails() {
const errorDetails = {
type: '<?= addslashes($errorData['type']) ?>',
message: '<?= addslashes($errorData['message']) ?>',
file: '<?= addslashes($errorData['file']) ?>',
line: <?= $errorData['line'] ?>,
timestamp: '<?= $errorData['timestamp'] ?>',
trace: <?= json_encode($errorData['trace']) ?>
};
const text = `Error Details:
Type: ${errorDetails.type}
Message: ${errorDetails.message}
File: ${errorDetails.file}
Line: ${errorDetails.line}
Timestamp: ${errorDetails.timestamp}
Stack Trace:
${JSON.stringify(errorDetails.trace, null, 2)}`;
navigator.clipboard.writeText(text).then(() => {
alert('Error details copied to clipboard!');
}).catch(err => {
console.error('Failed to copy: ', err);
alert('Failed to copy error details');
});
}
// Auto-expand first section
document.addEventListener('DOMContentLoaded', () => {
toggleSection('details');
toggleSection('trace');
});
</script>
</body>
</html>